open-nomad/vendor/github.com/hashicorp/go-memdb/memdb.go

93 lines
2.2 KiB
Go
Raw Normal View History

2016-02-12 18:02:16 +00:00
package memdb
import (
"sync"
2016-02-16 01:38:08 +00:00
"sync/atomic"
"unsafe"
2016-02-12 18:02:16 +00:00
"github.com/hashicorp/go-immutable-radix"
)
// MemDB is an in-memory database. It provides a table abstraction,
// which is used to store objects (rows) with multiple indexes based
// on values. The database makes use of immutable radix trees to provide
// transactions and MVCC.
type MemDB struct {
2017-08-31 00:45:32 +00:00
schema *DBSchema
root unsafe.Pointer // *iradix.Tree underneath
2017-02-04 00:28:27 +00:00
primary bool
2016-02-12 18:02:16 +00:00
// There can only be a single writter at once
writer sync.Mutex
}
// NewMemDB creates a new MemDB with the given schema
func NewMemDB(schema *DBSchema) (*MemDB, error) {
// Validate the schema
if err := schema.Validate(); err != nil {
return nil, err
}
// Create the MemDB
db := &MemDB{
2017-08-31 00:45:32 +00:00
schema: schema,
root: unsafe.Pointer(iradix.New()),
2017-02-04 00:28:27 +00:00
primary: true,
2016-02-12 18:02:16 +00:00
}
if err := db.initialize(); err != nil {
return nil, err
}
return db, nil
}
2016-02-16 01:38:08 +00:00
// getRoot is used to do an atomic load of the root pointer
func (db *MemDB) getRoot() *iradix.Tree {
root := (*iradix.Tree)(atomic.LoadPointer(&db.root))
return root
}
2016-02-12 18:02:16 +00:00
// Txn is used to start a new transaction, in either read or write mode.
// There can only be a single concurrent writer, but any number of readers.
func (db *MemDB) Txn(write bool) *Txn {
if write {
db.writer.Lock()
}
txn := &Txn{
db: db,
write: write,
2016-02-16 01:38:08 +00:00
rootTxn: db.getRoot().Txn(),
2016-02-12 18:02:16 +00:00
}
return txn
}
// Snapshot is used to capture a point-in-time snapshot
// of the database that will not be affected by any write
// operations to the existing DB.
func (db *MemDB) Snapshot() *MemDB {
clone := &MemDB{
2017-08-31 00:45:32 +00:00
schema: db.schema,
root: unsafe.Pointer(db.getRoot()),
2017-02-04 00:28:27 +00:00
primary: false,
2016-02-12 18:02:16 +00:00
}
return clone
}
// initialize is used to setup the DB for use after creation
func (db *MemDB) initialize() error {
2016-02-16 01:38:08 +00:00
root := db.getRoot()
2016-02-12 18:02:16 +00:00
for tName, tableSchema := range db.schema.Tables {
2017-08-31 00:45:32 +00:00
for iName := range tableSchema.Indexes {
2016-02-12 18:02:16 +00:00
index := iradix.New()
path := indexPath(tName, iName)
2016-02-16 01:38:08 +00:00
root, _, _ = root.Insert(path, index)
2016-02-12 18:02:16 +00:00
}
}
2016-02-16 01:38:08 +00:00
db.root = unsafe.Pointer(root)
2016-02-12 18:02:16 +00:00
return nil
}
// indexPath returns the path from the root to the given table index
func indexPath(table, index string) []byte {
return []byte(table + "." + index)
}