Skip to content

Lock-free MPMC Ring Buffer (Generic) for SMP, in golang. Some posts in chinese:

License

Notifications You must be signed in to change notification settings

hedzr/go-ringbuf

Repository files navigation

go-ringbuf [V2]

Go GitHub tag (latest SemVer) go.dev GoDoc FOSSA Status Go Report Card Coverage Status

go-ringbuf provides a high-performance, lock-free circular queue (ring buffer) implementation in golang.

MPMC (multiple producers and multiple consumers) enabled.

History

v2.2.0

  • added new impl to support overlapped ringbuf
  • security updates

v2.1.0

  • remove extras deps
    • replaced 'hedzr/log' with 'log/slog', 'hedzr/errors.v3' with 'errors'
  • remove WithLogger()

v2.0.+

security updates

v2.0.0 @20220408 - go 1.18+

generic version for MPMC Ring Buffer.

  • rewritten with go generics

v1.0.+ [archived]

security updates

v1.0.0 @20220408

Last release for classical version.

Next release (v2) will move to go 1.18+ with generic enabled.

v0.9.1 @2022

  • review all codes
  • updated deps
  • review and solve uncertain misreport failed licenses
    • we have two deps: hedzr/errors and hedzr/log, and both them have no 3rd-party deps.
      • since 2.1.0, any deps removed.
    • we have no more 3rd-party deps.
    • we assumed a free license under MIT (unified).

Getting Start

go get -v github.com/hedzr/go-ringbuf/v2

Samples

package main

import (
 "fmt"
 "log"

 "github.com/hedzr/go-ringbuf/v2"
)

func main() {
 testIntRB()
 testStringRB()
}

func testStringRB() {
 var err error
 var rb = ringbuf.New[string](80)
 err = rb.Enqueue("abcde")
 errChk(err)

 var item string
 item, err = rb.Dequeue()
 errChk(err)
 fmt.Printf("dequeue ok: %v\n", item)
}

func testIntRB() {
 var err error
 var rb = ringbuf.New[int](80)
 err = rb.Enqueue(3)
 errChk(err)

 var item int
 item, err = rb.Dequeue()
 errChk(err)
 fmt.Printf("dequeue ok: %v\n", item)
}

func errChk(err error) {
 if err != nil {
  log.Fatal(err)
 }
}

Using Ring-Buffer as a fixed resource pool

The following codes is for v1, needed for rewriting

func newRes() *Res{...}

var rb fast.RingBuffer

func initFunc() (err error) {
  const maxSize = 16
  
  if rb = fast.New(uint32(maxSize)); rb == nil {
  err = errors.New("cannot create fast.RingBuffer")
  return
 }

    // CapReal() will be available since v0.8.8, or replace it with Cap() - 1
 for i := uint32(0); i < rb.CapReal(); i++ {
  if err = rb.Enqueue(newRes()); err != nil {
   return
  }
 }
}

func loopFor() {
  var err error
  for {
    it, err := rb.Dequeue()
    checkErr(err)
    if res, ok := it.(*Res); ok {
      // do stuff with `res`, and put it back into ring-buffer
      err = rb.Enqueue(it)
    }
  }
}

Using Overlapped Ring Buffer

Since v2.2.0, NewOverlappedRingBuffer() can initiate a different ring buffer, which allows us to overwrite the head element if putting new element into a full ring buffer.

func testStringRB() {
 var err error
 var rb = ringbuf.NewOverlappedRingBuffer[string](80)
 err = rb.Enqueue("abcde")
 errChk(err)

 var item string
 item, err = rb.Dequeue()
 errChk(err)
 fmt.Printf("dequeue ok: %v\n", item)
}

Contrib

Welcome

LICENSE

Apache 2.0