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

Folders and files

NameName
Last commit message
Last commit date

Latest commit

cd7c766 · Jul 29, 2022

History

10 Commits
Mar 28, 2022
Mar 28, 2022
Mar 28, 2022
Mar 28, 2022
Jul 26, 2022
Mar 28, 2022
Mar 28, 2022
Mar 28, 2022
Mar 28, 2022
Mar 28, 2022
Mar 28, 2022
Jul 26, 2022
Mar 28, 2022
Mar 28, 2022

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()
        }
    }
}