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 ¶
- type Store
- func (store Store) Absorb(store2 Store)
- func (store Store) Delete(key string)
- func (store Store) DeleteTimestamped(key string, timestamp int64)
- func (store Store) Get(key string) string
- func (store Store) Hash() string
- func (store Store) Purge(cutoff int64)
- func (store Store) Set(key string, value string)
- func (store Store) SetTimestamped(key string, value string, timestamp int64)
- func (store Store) SimpleString() string
- func (store Store) String() string
- type ValueTimestamp
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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>