Skip to content

rayleyva/fdb-go

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

75 Commits
 
 
 
 
 
 
 
 

Repository files navigation

fdb-go

Go language bindings for FoundationDB, a distributed key-value store with ACID transactions.

This package is currently targetting FoundationDB 1.0.0 (API version 100), and is a work in progress. In particular, there is not yet complete coverage of the FoundationDB API, and the interface will almost certainly change in breaking ways.

Example

Until there's proper documentation, here's a quick code snippet.

package main

import (
	"github.com/FoundationDB/fdb-go/fdb"
	"log"
	"fmt"
	"sync"
)

func main() {
	err := fdb.APIVersion(100)
	if err != nil {
		log.Fatal(err)
	}

	db, err := fdb.OpenDefault()
	if err != nil {
		log.Fatal(err)
	}

	// db.Transact will create a new transaction and commit it for you,
	// retrying the function as necessary. The calling goroutine will be
	// blocked until success or non-retryable error.
	//
	// In this example, we are ignoring the possible return value of the
	// transactional function.
	_, err = db.Transact(func (tr *fdb.Transaction) (interface{}, error) {
		tr.ClearRange([]byte("go"), []byte("gp"))
		tr.Set([]byte("gofoo"), []byte("hello"))
		tr.Set([]byte("gobar"), []byte("world"))
		return nil, nil
	})
	if err != nil {
		log.Fatal(err)
	}

	wg := sync.WaitGroup{}
	ch := make(chan struct{})

	wg.Add(1)
	go func() {
		ret, err := db.Transact(func (tr *fdb.Transaction) (interface{}, error) {
			// tr.Get() is a "future" representing an asynchronous
			// result, and does not block.
			fv1 := tr.Get([]byte("gofoo"))
			fv2 := tr.Get([]byte("gobar"))

			// GetOrPanic() will block until the future is ready,
			// and panic any FoundationDB errors, allowing
			// db.Transact() to recover and (possibly) retry the
			// transaction.
			v1 := fv1.GetOrPanic()
			// GetWithError() also blocks, but allows us to handle
			// the error ourselves. It's still important that we
			// check the error and return it if non-nil, allowing
			// db.Transact() to react appropriately.
			v2, e := fv2.GetWithError()
			if e != nil {
				return nil, e
			}

			fmt.Println("inside first goroutine\n  gofoo:", string(v1), "\n  gobar:", string(v2))

			// Wait for the other goroutine to finish, which should
			// trigger a conflict in this transaction.
			<- ch

			tr.Set([]byte("gofoo"), []byte("aloha"))

			// We can return anything that implements interface{},
			// along with an error. Here we are returning the
			// last-seen values of gofoo and gobar before our own
			// set.
			return &struct{a, b string}{string(v1), string(v2)}, nil
		})
		if err != nil {
			log.Fatal(err)
		}

		fmt.Println("first goroutine returned:", ret)
		wg.Done()
	}()

	wg.Add(1)
	go func() {
		w, err := db.Transact(func (tr *fdb.Transaction) (interface{}, error) {
			tr.Set([]byte("gofoo"), []byte("hola"))
			return tr.Watch([]byte("gofoo")), nil
		})
		if err != nil {
			log.Fatal(err)
		}

		fmt.Println("second goroutine modified gofoo")

		// Let the first goroutine proceed.
		close(ch)

		// This watch should trigger once the first goroutine
		// successfully commits a change to "gofoo".
		err = w.(*fdb.FutureNil).GetWithError()
		fmt.Println("watch triggered on gofoo")
		wg.Done()
	}()

	wg.Wait()
}

About

Go bindings for FoundationDB

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published