Skip to content
/ garr Public

Collection of high performance, thread-safe, lock-free go data structures

License

Notifications You must be signed in to change notification settings

line/garr

Repository files navigation

Garr - Go libs in a Jar

Go Reference CI Go Report Card

Collection of high performance, thread-safe, lock-free go data structures.

  • adder - Data structure to perform highly-performant sum under high contention. Inspired by OpenJDK LongAdder
  • circuit-breaker - Data structure to implement circuit breaker pattern to detect remote service failure/alive status.
  • queue - Queue data structure, go implementation of JDKLinkedQueue and MutexLinkedQueue from OpenJDK.
  • retry - Controls backoff between attempts in a retry operation.
  • worker-pool - Worker pool implementation in go to help perform multiple tasks concurrently with a fixed-but-expandable amount of workers.

Usage

Getting started

go get -u go.linecorp.com/garr

Examples

Please find detailed examples in each sub-package.

Adder

package main

import (
	"fmt"
	"time"

	ga "go.linecorp.com/garr/adder"
)

func main() {
	// or ga.DefaultAdder() which uses jdk long-adder as default
	adder := ga.NewLongAdder(ga.JDKAdderType) 

	for i := 0; i < 100; i++ {
		go func() {
			adder.Add(123)
		}()
	}

	time.Sleep(3 * time.Second)

	// get total added value
	fmt.Println(adder.Sum()) 
}

Build your own Prometheus counter with Adder

package prom

import (
	ga "go.linecorp.com/garr/adder"

	"github.com/prometheus/client_golang/prometheus"
	dto "github.com/prometheus/client_model/go"
)

// NewCounterI64 creates a new CounterI64 based on the provided prometheus.CounterOpts.
func NewCounterI64(opts prometheus.CounterOpts) CounterI64 {
	return CounterI64{counter: prometheus.NewCounter(opts)}
}

// CounterI64 is optimized Prometheus Counter for int64 value type.
type CounterI64 struct {
	val     ga.JDKAdder
	counter prometheus.Counter
}

// Value returns current value.
func (c *CounterI64) Value() int64 {
	return c.val.Sum()
}

// Reset value.
func (c *CounterI64) Reset() {
	c.val.Reset()
}

// Desc returns metric desc.
func (c *CounterI64) Desc() *prometheus.Desc {
	return c.counter.Desc()
}

// Inc by 1.
func (c *CounterI64) Inc() {
	c.val.Add(1)
}

// Add by variant.
func (c *CounterI64) Add(val int64) {
	if val > 0 {
		c.val.Add(val)
	}
}

// Write implements prometheus.Metric interface.
func (c *CounterI64) Write(out *dto.Metric) (err error) {
	if err = c.counter.Write(out); err == nil {
		value := float64(c.val.Sum())
		out.Counter.Value = &value
	}
	return
}

// Collect implements prometheus.Collector interface.
func (c *CounterI64) Collect(ch chan<- prometheus.Metric) {
	ch <- c
}

// Describe implements prometheus.Collector interface.
func (c *CounterI64) Describe(ch chan<- *prometheus.Desc) {
	ch <- c.counter.Desc()
}

Queue

package main

import (
    "fmt"

    "go.linecorp.com/garr/queue"
)

func main() {
    q := queue.DefaultQueue() // default using jdk linked queue

    // push
    q.Offer(123)

    // return head queue but not remove
    head := q.Peek()
    fmt.Println(head)

    // remove and return head queue
    polled := q.Poll()
    fmt.Println(polled)
}

Circuit Breaker

package main

import (
    cbreaker "go.linecorp.com/garr/circuit-breaker"
)

func makeRequest() error {
	return nil
}

func main() {
    cb := cbreaker.NewCircuitBreakerBuilder().
                        SetTicker(cbreaker.SystemTicker).
                        SetFailureRateThreshold(validFailureRateThreshold).
                        Build()

    if cb.CanRequest() {
        err := makeRequest()
        if err != nil {
            cb.OnFailure()
        } else {
            cb.OnSuccess()
        }
    }
}