tpjg/goriakpbc — pull request #81 by Vagabond (2014-08-08 01:17:15+00:00)
Title: Implement Riak 2.0 bucket type and CRDTs

In addition, implementing bucket types provides access to strong consistency as well, which I have also tested.

For more on CRDTs there's a good overview here: http://blog.joeljacobson.com/riak-2-0-data-types/

The new bucket type api is pretty simple, instead of getting a bucket, you get a bucket type

bucket, err := riak.NewBucketType("counters", "tstriak")

You can then query it normally, or use the new Fetch operations on it:

obj, err := bucket.FetchCounter("tstobj")
obj, err := bucket.FetchSet("tstobj2")
obj, err := bucket.FetchMap("tstobj2")

The CRDT type depends on the bucket type configuation, if you try to fetch the wrong type from a bucket storing a different type, a type assertion will fail.

All 3 CRDTs implement the following:

obj.GetValue()
obj.Destroy()
obj.Store()

Counters have 1 operation:

obj.Increment(int64)

Negative increments are decrements.

Sets have 2 operations:

obj.Add([]byte)
obj.Remove([]byte)

Maps can contain any of the above 3 CRDT types, with the addition of Flags and Registers

Flags are a effectively a boolean and have 2 operations:

obj.Enable()
obj.Disable()

Registers are a 'last write wins' field and support one operation:

obj.Update([]byte)

Maps themselves have 3 'familes' of operations

obj.AddFlag(string)
obj.FetchFlag(string)
obj.RemoveFlag(string)

Add/Fetch/Remove are implemented for all 5 CRDT types. The difference between Add and Fetch is that Fetch will return nil if the key is not already present in the map. Maps include the CRDT type in the key, so you have have 2 keys with the same name as long as the types differ.

Maps also have a Print() function that prints the map's representation to stdout (I don't know how to print to a buffer in Go).

```
{
{hello2 MAP} - {
{hello COUNTER} - 5
{hello3 SET} - [
fish
tacos
]
{hello2 FLAG} - true
{hello2 REGISTER} - goodbye
{hello2 COUNTER} - 5
}
{hello SET} - [
bacon
chunky
]
{hello FLAG} - false
{hello REGISTER} - hello
{hello COUNTER} - 1
}
```

In general I'm not terribly great with Go, so let me know if I did anything really badly and I will try to find the time to fix it, although my available time for this will be limited as I'm trying to migrate off the Go codebase I wrote this for.