gocowvalue

package module
v0.0.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 17, 2021 License: Apache-2.0 Imports: 3 Imported by: 1

README

Go Report Card GitHub license GitHub go.mod Go version

go-copyonwrite-loader

A simple tiny config loader by using copy-on-write idea.

motivation

Like the Java's CopyOnWriteArray, this tiny library implements the similar idea, but not only scoped to the array. Mutex can be used in a read/write concurrency environment, but not ideal in a write-less-read-more situation.

This library is developed for reloading value in a write-less-read-more situation. To be more specific, the Loader accepts and buffers the modifications (called Op) on the value, periodically apply them on the value and reload it. The old value will be GC as long as it is not referenced any more.

example

package  main

// op implements the Op interface
type op int
func (o op) Type() string         { return "dummy" }
func (o op) Context() interface{} { return (int)(o) }

// copy-on-write array implements the Value interface: Copy and Apply.
type cowArray struct {
	arr []int
}

// Copy() will deep-copy the value itself, this is important because if a pointer is still shared or shadow copied, the old value won't be GC.
func (c *cowArray) Copy() Value {
	r := make([]int, len(c.arr))
	copy(r, c.arr)

	return &cowArray{
		arr: r,
	}
}

// Apply() will apply the modification ops on the new value in the order as it is.
func (c *cowArray) Apply(ops []Op) error {
	for _, o := range ops {
		v := o.Context().(int)
		c.arr = append(c.arr, v)
	}
	return nil
}


func main() {

    c := &cowArray{}
	r := New(c, 1)
	errChan := r.Err()

	go func() {
		for {
			select {
			case err := <-errChan:
				t.Error(err)
			}
		}
	}()

	for i := 0; i < 100; i++ {
		go func() {
			for {
				time.Sleep(1 * time.Second)
                		// Accept is concurrent-safe, can be used by multiple go-routines
				r.Accept(op(1))
			}
		}()
	}

	for i := 0; i < 10; i++ {
		time.Sleep(1 * time.Second)
       		// Reload is concurrent-safe, can be used by multiple go-routines
		v := r.Reload().(*cowArray)
		fmt.Printf("%d \n", len(v.arr))
	}

    // it should print like 
    // 101
    // 200
    // 300
    // 400
    // 500
    // 600
    // 700
    // 800
    // 900
}

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Op

type Op interface {
	Type() string
	Context() interface{}
}

Op defines the modification that will be applied on Value.

type Reloader

type Reloader struct {
	// contains filtered or unexported fields
}

Reloader reloads a value periodically by using a copy-on-write mechanism.

func New

func New(v Value, freshFreq int) *Reloader

New creates a new loader for v, and periodically refresh it.

func (*Reloader) Accept

func (r *Reloader) Accept(op Op) error

Accept appends the modification op into a queue, note that all the ops are not applied immediately but in a batch fashion once the ticker is triggered.

func (*Reloader) Err

func (r *Reloader) Err() <-chan error

Err returns an error channel.

func (*Reloader) Reload

func (r *Reloader) Reload() Value

Reload returns the latest snapshot of value. The loaded value is not guaranteed to contain all the modifications, see Accept(op Op).

type Value

type Value interface {
	Copy() Value
	Apply(ops []Op) error
}

Value provides 2 functions in order to fulfill the copy-on-write: Copy() will deep-copy the value itself, this is important because if a pointer is still shared or shadow copied, the old value won't be GC. Apply() will apply the modification ops on the new value in the order as it is.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL