kvt

package module
v0.0.0-...-902cc49 Latest Latest
Warning

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

Go to latest
Published: Aug 18, 2017 License: BSD-3-Clause Imports: 5 Imported by: 0

README

KVT - A Simple Key|Value|Timestamp Store

Package kvt offers a simple Key|Value|Timestamp store.

You can merge multiple Stores and the resulting Store will have the newest Key|Value|Timestamp triplets.

This store might be useful where you have a small set of metadata and want to allow updates to it on multiple machines to sync up later.

It offers a Hash to quickly identify if there are any changes, and offers JSON marshaling and unmarshaling for persistence.

API Documentation

Copyright See AUTHORS. All rights reserved.
Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file.

Example Usage

package main

import (
    "fmt"

    "github.com/gholt/kvt"
)

func main() {
    // Create store with a few items.
    store1 := kvt.Store{}
    store1.Set("A", "one")
    store1.Set("B", "two")
    store1.Set("C", "three")

    // Create another store with other items, some overlapping, some
    // deleting, some new.
    store2 := kvt.Store{}
    store2.Delete("B")
    store2.Set("C", "four")
    store2.Set("D", "five")
    store2.Set("E", "six")
    store2.Set("F", "seven")

    // For extra effort, update and delete items on the first store.
    store1.Set("E", "eight")
    store1.Delete("F")

    // Here they are prior to merging.
    fmt.Println("Store1:", store1.SimpleString())
    fmt.Println("Store2:", store2.SimpleString())

    // Now we merge store2 into store1.
    store1.Absorb(store2)
    fmt.Println()

    fmt.Println("Store1:", store1.SimpleString())

    // Output:
    // Store1: A=one,B=two,C=three,E=eight,F/deleted
    // Store2: B/deleted,C=four,D=five,E=six,F=seven
    //
    // Store1: A=one,B/deleted,C=four,D=five,E=eight,F/deleted
}

Documentation

Overview

Package kvt offers a simple Key|Value|Timestamp store.

You can merge multiple Stores and the resulting Store will have the newest Key|Value|Timestamp triplets.

This store might be useful where you have a small set of metadata and want to allow updates to it on multiple machines to sync up later.

It offers a Hash to quickly identify if there are any changes, and offers JSON marshaling and unmarshaling for persistence.

Example (Overview)
package main

import (
	"fmt"

	"github.com/gholt/kvt"
)

func main() {
	// Create store with a few items.
	store1 := kvt.Store{}
	store1.Set("A", "one")
	store1.Set("B", "two")
	store1.Set("C", "three")

	// Create another store with other items, some overlapping, some deleting,
	// some new.
	store2 := kvt.Store{}
	store2.Delete("B")
	store2.Set("C", "four")
	store2.Set("D", "five")
	store2.Set("E", "six")
	store2.Set("F", "seven")

	// For extra effort, update and delete items on the first store.
	store1.Set("E", "eight")
	store1.Delete("F")

	// Here they are prior to merging.
	fmt.Println("Store1:", store1.SimpleString())
	fmt.Println("Store2:", store2.SimpleString())

	// Now we merge store2 into store1.
	store1.Absorb(store2)
	fmt.Println()

	fmt.Println("Store1:", store1.SimpleString())

}
Output:

Store1: A=one,B=two,C=three,E=eight,F/deleted
Store2: B/deleted,C=four,D=five,E=six,F=seven

Store1: A=one,B/deleted,C=four,D=five,E=eight,F/deleted

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Store

type Store map[string]*ValueTimestamp

Store is a Key|Value|Timestamp simple store.

Example
package main

import (
	"fmt"

	"github.com/gholt/kvt"
)

func main() {
	// Create store with a few items.
	store1 := kvt.Store{}
	store1.Set("A", "one")
	store1.Set("B", "two")
	store1.Set("C", "three")

	// Create another store with other items, some overlapping, some deleting,
	// some new.
	store2 := kvt.Store{}
	store2.Delete("B")
	store2.Set("C", "four")
	store2.Set("D", "five")
	store2.Set("E", "six")
	store2.Set("F", "seven")

	// For extra effort, update and delete items on the first store.
	store1.Set("E", "eight")
	store1.Delete("F")

	// Here they are prior to merging.
	fmt.Println("Store1:", store1.SimpleString())
	fmt.Println("Store2:", store2.SimpleString())

	// Now we merge store2 into store1.
	store1.Absorb(store2)
	fmt.Println()

	fmt.Println("Store1:", store1.SimpleString())

}
Output:

Store1: A=one,B=two,C=three,E=eight,F/deleted
Store2: B/deleted,C=four,D=five,E=six,F=seven

Store1: A=one,B/deleted,C=four,D=five,E=eight,F/deleted

func (Store) Absorb

func (store Store) Absorb(store2 Store)

Absorb will update store with any newer items from store2; after Absorb, you should no longer use store2.

Example
package main

import (
	"fmt"

	"github.com/gholt/kvt"
)

func main() {
	// Create store with a few items.
	store1 := kvt.Store{}
	store1.Set("A", "one")
	store1.Set("B", "two")
	store1.Set("C", "three")

	// Create another store with other items, some overlapping, some deleting,
	// some new.
	store2 := kvt.Store{}
	store2.Delete("B")
	store2.Set("C", "four")
	store2.Set("D", "five")
	store2.Set("E", "six")
	store2.Set("F", "seven")

	// For extra effort, update and delete items on the first store.
	store1.Set("E", "eight")
	store1.Delete("F")

	// Here they are prior to merging.
	fmt.Println("Store1:", store1.SimpleString())
	fmt.Println("Store2:", store2.SimpleString())

	// Now we merge store2 into store1.
	store1.Absorb(store2)
	fmt.Println()

	fmt.Println("Store1:", store1.SimpleString())

}
Output:

Store1: A=one,B=two,C=three,E=eight,F/deleted
Store2: B/deleted,C=four,D=five,E=six,F=seven

Store1: A=one,B/deleted,C=four,D=five,E=eight,F/deleted

func (Store) Delete

func (store Store) Delete(key string)

Delete is equivalent to DeleteTimestamped(key, time.Now().UnixNano()).

Example
package main

import (
	"fmt"

	"github.com/gholt/kvt"
)

func main() {
	store := kvt.Store{}
	store.Delete("A")
	fmt.Println(store.SimpleString())

}
Output:

A/deleted

func (Store) DeleteTimestamped

func (store Store) DeleteTimestamped(key string, timestamp int64)

DeleteTimestamped records a deletion marker for the key as long as there isn't already a value for that key with a newer or equal timestamp.

Example
package main

import (
	"fmt"
	"time"

	"github.com/gholt/kvt"
)

func main() {
	store := kvt.Store{}
	store.DeleteTimestamped("A", time.Date(2017, 1, 2, 3, 4, 5, 6, time.UTC).UnixNano())
	store.DeleteTimestamped("A", 1) // Discarded as old
	store.SetTimestamped("B", "two", 2)
	store.DeleteTimestamped("B", 1) // Discarded as old
	store.SetTimestamped("C", "three", 3)
	store.DeleteTimestamped("C", 4)
	fmt.Println(store)

}
Output:

{"A":[null,1483326245000000006],"B":["two",2],"C":[null,4]}

func (Store) Get

func (store Store) Get(key string) string

Get returns the value for a key; if the key does not exist or is marked deleted, an empty string is returned.

Example
package main

import (
	"fmt"

	"github.com/gholt/kvt"
)

func main() {
	store := kvt.Store{}
	store.Set("A", "one")
	store.Delete("B")
	for _, k := range []string{"A", "B", "C"} {
		fmt.Printf("Get(%q): %q\n", k, store.Get(k))
	}

}
Output:

Get("A"): "one"
Get("B"): ""
Get("C"): ""

func (Store) Hash

func (store Store) Hash() string

Hash returns a computed hash string that can be used to quickly detect if two stores are in sync.

Example
package main

import (
	"fmt"
	"time"

	"github.com/gholt/kvt"
)

func main() {
	store1 := kvt.Store{}
	now := time.Date(2017, 1, 2, 3, 4, 5, 6, time.UTC).UnixNano()
	store1.SetTimestamped("A", "one", now)
	store1.SetTimestamped("B", "two", now)
	store1.SetTimestamped("C", "three", now)
	fmt.Println("store1 has hash", store1.Hash())
	store2 := kvt.Store{}
	store2.SetTimestamped("A", "one", now)
	store2.SetTimestamped("B", "two", now)
	store2.SetTimestamped("C", "three", now)
	fmt.Println("store2 has hash", store2.Hash())
	store2.SetTimestamped("C", "three", now+1)
	fmt.Println("store2 now has hash", store2.Hash())

}
Output:

store1 has hash 3d6a6976bcf5dfb9
store2 has hash 3d6a6976bcf5dfb9
store2 now has hash 3d670f76bcf310f4

func (Store) Purge

func (store Store) Purge(cutoff int64)

Purge discards any deletion markers older than the cutoff timestamp given.

Example
package main

import (
	"fmt"
	"time"

	"github.com/gholt/kvt"
)

func main() {
	store := kvt.Store{}
	now := time.Date(2017, 1, 2, 3, 4, 5, 6, time.UTC)
	store.DeleteTimestamped("A", now.Add(-1001*time.Hour).UnixNano())
	store.DeleteTimestamped("B", now.Add(-1000*time.Hour).UnixNano())
	store.DeleteTimestamped("C", now.Add(-999*time.Hour).UnixNano())
	fmt.Println("Before:", store)
	store.Purge(now.Add(-1000 * time.Hour).UnixNano())
	fmt.Println("After:", store)

}
Output:

Before: {"A":[null,1479722645000000006],"B":[null,1479726245000000006],"C":[null,1479729845000000006]}
After: {"B":[null,1479726245000000006],"C":[null,1479729845000000006]}

func (Store) Set

func (store Store) Set(key string, value string)

Set is equivalent to SetTimestamped(key, value, time.Now().UnixNano()).

Example
package main

import (
	"fmt"

	"github.com/gholt/kvt"
)

func main() {
	store := kvt.Store{}
	store.Set("A", "one")
	fmt.Println(store.SimpleString())

}
Output:

A=one

func (Store) SetTimestamped

func (store Store) SetTimestamped(key string, value string, timestamp int64)

SetTimestamped stores the value for the key as long as there isn't already a value for that key with a newer or equal timestamp.

Example
package main

import (
	"fmt"
	"time"

	"github.com/gholt/kvt"
)

func main() {
	store := kvt.Store{}
	store.SetTimestamped("A", "one", time.Date(2017, 1, 2, 3, 4, 5, 6, time.UTC).UnixNano())
	fmt.Println(store)

}
Output:

{"A":["one",1483326245000000006]}

func (Store) SimpleString

func (store Store) SimpleString() string

SimpleString returns a simple key=value[,key=value] string form of the store contents; useful in tests when you want to omit the timestamps.

Example
package main

import (
	"fmt"
	"time"

	"github.com/gholt/kvt"
)

func main() {
	store := kvt.Store{}
	now := time.Date(2017, 1, 2, 3, 4, 5, 6, time.UTC).UnixNano()
	store.SetTimestamped("A", "one", now)
	store.DeleteTimestamped("B", now)
	fmt.Println(store.SimpleString())

}
Output:

A=one,B/deleted

func (Store) String

func (store Store) String() string

String returns the JSON encoded string representation of the store contents.

Example
package main

import (
	"fmt"
	"time"

	"github.com/gholt/kvt"
)

func main() {
	store := kvt.Store{}
	now := time.Date(2017, 1, 2, 3, 4, 5, 6, time.UTC).UnixNano()
	store.SetTimestamped("A", "one", now)
	store.DeleteTimestamped("B", now)
	fmt.Println(store.String())
	fmt.Println(store)

}
Output:

{"A":["one",1483326245000000006],"B":[null,1483326245000000006]}
{"A":["one",1483326245000000006],"B":[null,1483326245000000006]}

type ValueTimestamp

type ValueTimestamp struct {
	Value     *string
	Timestamp int64
}

ValueTimestamp is the Value|Timestamp pair stored for each Key. If Value is nil, it indicates a deletion marker. These deletion markers are usually purged after some time using Store.Purge.

Example
package main

import (
	"fmt"

	"github.com/gholt/kvt"
)

func main() {
	one := "one"
	vtA := &kvt.ValueTimestamp{Value: &one, Timestamp: 1}
	vtB := &kvt.ValueTimestamp{Value: nil, Timestamp: 2}
	store := kvt.Store{"A": vtA, "B": vtB}
	fmt.Println(store)
	// A bit simpler:
	store = kvt.Store{"A": {&one, 1}, "B": {nil, 2}}
	fmt.Println(store)

}
Output:

{"A":["one",1],"B":[null,2]}
{"A":["one",1],"B":[null,2]}

func (*ValueTimestamp) MarshalJSON

func (valueTimestamp *ValueTimestamp) MarshalJSON() ([]byte, error)

MarshalJSON returns the JSON encoded version of valueTimestamp or an error.

Example
package main

import (
	"fmt"

	"github.com/gholt/kvt"
)

func main() {
	one := "one"
	b, err := (&kvt.ValueTimestamp{Value: &one, Timestamp: 1}).MarshalJSON()
	fmt.Println(string(b), err)
	b, err = (&kvt.ValueTimestamp{Value: nil, Timestamp: 2}).MarshalJSON()
	fmt.Println(string(b), err)

}
Output:

["one",1] <nil>
[null,2] <nil>

func (*ValueTimestamp) String

func (valueTimestamp *ValueTimestamp) String() string

String returns a quick string representation of valueTimestamp.

Example
package main

import (
	"fmt"

	"github.com/gholt/kvt"
)

func main() {
	one := "one"
	vt1 := &kvt.ValueTimestamp{Value: &one, Timestamp: 1}
	vt2 := &kvt.ValueTimestamp{Value: nil, Timestamp: 2}
	fmt.Println(vt1.String(), vt2.String())
	fmt.Println(vt1, vt2)

}
Output:

one,1 nil,2
one,1 nil,2

func (*ValueTimestamp) UnmarshalJSON

func (valueTimestamp *ValueTimestamp) UnmarshalJSON(b []byte) error

MarshalJSON loads valueTimestamp with data from the JSON encoded b or returns an error.

Example
package main

import (
	"fmt"

	"github.com/gholt/kvt"
)

func main() {
	vt := &kvt.ValueTimestamp{}
	err := vt.UnmarshalJSON([]byte(`["one",1]`))
	fmt.Println(vt, err)
	vt = &kvt.ValueTimestamp{}
	err = vt.UnmarshalJSON([]byte(`[null,2]`))
	fmt.Println(vt, err)

}
Output:

one,1 <nil>
nil,2 <nil>

Jump to

Keyboard shortcuts

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