go-datastructures icon indicating copy to clipboard operation
go-datastructures copied to clipboard

RingBuffer's Offer returns false (queue full) even when there is space in queue

Open SharanSharathi opened this issue 5 years ago • 0 comments

As per documentation, rb.Offer should return false only when the queue is full:

// Offer adds the provided item to the queue if there is space.  If the queue
// is full, this call will return false.  An error will be returned if the
// queue is disposed.
func (rb *RingBuffer) Offer(item interface{}) (bool, error) {
	return rb.put(item, true)
}

But, when adding elements to queue by concurrently calling rb.Offer, It returns false even when there is enough space. The following test file can reproduce the issue.

package test

import (
	"sync"
	"testing"

	"github.com/Workiva/go-datastructures/queue"
)

func TestRingQueueOffer_parallel(t *testing.T) {
	size := 256
	parallelGoroutines := 8

	rb := queue.NewRingBuffer(uint64(size * parallelGoroutines))

	wg := new(sync.WaitGroup)
	wg.Add(parallelGoroutines)

	for i := 0; i < parallelGoroutines; i++ {
		go func(id int) {
			defer wg.Done()

			for el := 1; el <= size; el++ {
				ok, err := rb.Offer(el)
				if err != nil {
					t.Errorf("error in goroutine-%d: %v", id, err)
					return
				}

				if !ok {
					t.Errorf("queue full before expected on adding %d element, len: %d, cap: %d ", el, rb.Len(), rb.Cap())
				}
			}
		}(i)
	}

	wg.Wait()
}

On running the above test file, I got:

--- FAIL: TestRingQueueOffer_parallel (0.00s)
    ring_buffer_test.go:31: queue full before expected on adding 1 element, len: 49, cap: 2048 
    ring_buffer_test.go:31: queue full before expected on adding 256 element, len: 1391, cap: 2048 
    ring_buffer_test.go:31: queue full before expected on adding 1 element, len: 1730, cap: 2048 
FAIL
FAIL	command-line-arguments	0.028s
FAIL

SharanSharathi avatar Oct 28 '20 18:10 SharanSharathi