flotilla

package module
v0.0.0-...-da1c31d Latest Latest
Warning

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

Go to latest
Published: Aug 7, 2015 License: BSD-2-Clause Imports: 14 Imported by: 0

README

== Flotilla

Flotilla is a consensus, embedded and programmable database, intended as a building block for distributed databases.

Consensus -- All changes to a Flotilla database are replicated in a consistent order across all machines in the Flotilla cluster.

Embedded -- All read transactions are from local storage. Doesn't expose any external network APIs (that's your job).

Programmable -- All write modifications are done via user-defined functions. This is done to process the same state machine in the same order on all machines. There are example user-defined functions in lib.go and the examples on this page.

== Architecture

Flotilla is based on a straightforward combination of the Raft algorithm (link) with the LMDB embedded database. In Raft, all cluster operations happen in a single, defined order. Operations don't have to be idempotent, because they'll be executed in the same order in each machine, guaranteeing the same final state. This means we can give each write transaction a single atomic and consistent view of the database, while allowing simultaneous readers due to LMDB's MVCC mechanisms.

This allows for the following simple API:

// Commands are registered with members of the cluster on startup, and can be executed from 
// any member of the cluster in a consistent fashion.
// 
// Do not leak txn handles or cursor handles outside of the execution of a command.
// Keep these consistent across machines!  Consider using versioning in your
// command names.
type Command func(args [][]byte, txn WriteTxn) ([]byte, error)

type Result struct {
	Response []byte
	Err      error
}

type DB interface {
	// Opens a read transaction from our local copy of the database
	// This transaction represents a snapshot in time.  Concurrent and
	// subsequent writes will not affect it or be visible.
	//
	// Each Txn opened is guaranteed to be able to see the results of any
	// command, cluster-wide, that completed before the last successful command
	// executed from this node.
	//
	// If we are not leader, this method will execute a no-op command through raft before
	// returning a new txn in order to guarantee happens-before ordering
	// for anything that reached the leader before we called Read()
	Read() (Txn, error)

	// Executes a user defined command on the leader of the cluster, wherever that may be.
	// Commands are executed in a fixed, single-threaded order on the leader
	// and propagated to the cluster in a log where they are applied.
	// Returns immediately, but Result will not become available on the returned chan until
	// the command has been processed on the leader and replicated on this node.
	//
	// Visibility:  Upon receiving a successful Result from the returned channel,
	// our command and all previously successful commands from any machine
	// have been committed to the leader and to this machine's local storage,
	// and will be visible to all future Read() Txns on this node or the leader.
	// Other nodes aside from this node and the leader are guaranteed to execute
	// all commands in the same order, guaranteeing consistency with concurrent
	// commands across the cluster, but are not necessarily guaranteed
	// to have received this command yet.
	Command(cmdName string, args [][]byte) <-chan Result

	// returns true if we're leader, supplied for optimization purposes only.
	// you should not be polling this for correctness reasons, all state changes should happen as Commands
	IsLeader() bool

	// leader addr, same disclaimer as IsLeader()
	Leader() net.Addr

	// shuts down this instance
	Close() error
}

See api.go for more details on what you can do with a ReadTxn and a WriteTxn. (basically, get, scan, put)

See the DB constructors in server.go, tests and hopefully-written-soon examples for how to set up a cluster.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func NewMultiStream

func NewMultiStream(
	listen net.Listener,
	dial func(string, time.Duration) (net.Conn, error),
	advertise net.Addr,
	lg *log.Logger,
	serviceCodes ...byte,
) (map[byte]raft.StreamLayer, error)

Uses the provided list and dial functions, can be used to allow flotilla to share a bound port with another binary service.

func NewStdMultiStream

func NewStdMultiStream(
	bindAddr string,
	lg *log.Logger,
	serviceCodes ...byte,
) (map[byte]raft.StreamLayer, error)

For each unique serviceCode provided, returns a transport layer with accept() and dial() functions by connecting to the provided addr and 'dialing' the byte.

Connections are obtained from the returned transport layer's net.Listener interface.

Types

type Command

type Command func(args [][]byte, txn *mdb.Txn) ([]byte, error)

Commands are registered with members of the cluster on startup Do not leak txn handles or cursor handles outside of the execution of a command. Keep these consistent across machines! Consider using versioning in your command names.

type DB

type DB interface {
	// Opens a read transaction from our local copy of the database
	// This transaction represents a snapshot in time.  Concurrent and
	// subsequent writes will not affect it or be visible.
	//
	// Each Txn opened is guaranteed to be able to see the results of any
	// command, cluster-wide, that completed before the last successful command
	// executed from this node.
	//
	// If we are not leader, this command will execute a no-op command through raft before
	// returning a new txn in order to guarantee happens-before ordering
	// for anything that reached the leader before we called Read()
	Read() (*mdb.Txn, error)

	// Executes a user defined command on the leader of the cluster, wherever that may be.
	// Commands are executed in a fixed, single-threaded order on the leader
	// and propagated to the cluster in a log where they are applied.
	// Returns immediately, but Result will not become available on the returned chan until
	// the command has been processed on the leader and replicated on this node.
	//
	// Visibility:  Upon receiving a successful Result from the returned channel,
	// our command and all previously successful commands cluster-wide
	// have been committed to the leader and to local storage,
	// and will be visible to all future Read() Txns on this node or the leader.
	// Other nodes aside from this node and the leader are guaranteed to execute
	// all commands in the same order, guaranteeing consistency with concurrent
	// commands across the cluster, but are not necessarily guaranteed
	// to have received this command yet.
	Command(cmdName string, args [][]byte) <-chan Result

	// returns true if we're leader, supplied for optimization purposes only.
	// you should not be polling this for correctness reasons, all state changes should happen as Commands
	IsLeader() bool

	// leader addr, same disclaimer as IsLeader()
	Leader() net.Addr

	// removes a peer if you detected a failure from outside of flotilla
	RemovePeer(peer net.Addr) error

	// shuts down this instance
	Close() error
}

Represents a DB. DBs work as peers in a cluster. At any given time, some peer is the leader and all updates move through that leader in single-threaded fashion and distributed to followers in a consistent ordering. Read operations are done against local data.

func NewDB

func NewDB(
	peers []string,
	dataDir string,
	listen net.Listener,
	dialer func(string, time.Duration) (net.Conn, error),
	commands map[string]Command,
	lg *log.Logger) (DB, error)

Instantiates a new DB serving the ops provided, using the provided dataDir and listener If Peers is empty, we start as the sole leader. Otherwise, connect to the existing leader.

type DefaultOpsDB

type DefaultOpsDB interface {
	DB
	// built-in Put command, returns empty bytes
	Put(dbName string, key, val []byte) <-chan Result
	// built-in Remove command, returns empty bytes
	Remove(dbName string, key []byte) <-chan Result
	// built-in PutIfAbsent command, returns [1] if put succeeded, [0] if not
	PutIfAbsent(dbName string, key, val []byte) <-chan Result
	// built-in Compare and Swap command, returns value after execution
	CompareAndSwap(dbName string, key, expectedVal, setVal []byte) <-chan Result
	// built-in Compare and Remove, returns [1] if removed, [0] if not
	CompareAndRemove(dbName string, key, expectedVal []byte) <-chan Result
	// No-op command, useful for creating a happens-before barrier, returns empty bytes
	Barrier() <-chan Result
}

we implement a few standard utility ops on top of the BaseDB

func NewDefaultDB

func NewDefaultDB(peers []string, dataDir string, bindAddr string, ops map[string]Command) (DefaultOpsDB, error)

launches a new DB serving out of dataDir

type Result

type Result struct {
	Response []byte
	Err      error
}

type TCPStreamLayer

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

TCPStreamLayer implements raft.StreamLayer interface

func (*TCPStreamLayer) Accept

func (t *TCPStreamLayer) Accept() (c net.Conn, err error)

Accept implements the net.Listener interface.

func (*TCPStreamLayer) Dial

func (t *TCPStreamLayer) Dial(address string, timeout time.Duration) (net.Conn, error)

Dial implements the StreamLayer interface.

Directories

Path Synopsis
Godeps
_workspace/src/github.com/hashicorp/go-msgpack/codec
High Performance, Feature-Rich Idiomatic Go encoding library for msgpack and binc .
High Performance, Feature-Rich Idiomatic Go encoding library for msgpack and binc .
_workspace/src/github.com/jbooth/gomdb
A thin wrapper for the lmdb C library.
A thin wrapper for the lmdb C library.
_workspace/src/github.com/ugorji/go/codec
High Performance, Feature-Rich Idiomatic Go encoding library for msgpack and binc .
High Performance, Feature-Rich Idiomatic Go encoding library for msgpack and binc .

Jump to

Keyboard shortcuts

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