Workiva / go-datastructures

A collection of useful, performant, and threadsafe Go datastructures.
Apache License 2.0
7.66k stars 834 forks source link

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

Open SharanSharathi opened 4 years ago

SharanSharathi commented 4 years ago

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