package mdb import ( "net" "os" "path/filepath" "sync" "git.crumpington.com/private/mdb/kvstore" "golang.org/x/sys/unix" ) type Database struct { root string lock *os.File kv *kvstore.KV collections map[string]dbCollection } func NewPrimary(root string) *Database { return newDB(root, true) } func NewSecondary(root string) *Database { return newDB(root, false) } func newDB(root string, primary bool) *Database { must(os.MkdirAll(root, 0700)) lockPath := filepath.Join(root, "lock") // Acquire the lock. lock, err := os.OpenFile(lockPath, os.O_RDWR|os.O_CREATE, 0600) must(err) must(unix.Flock(int(lock.Fd()), unix.LOCK_EX)) db := &Database{ root: root, collections: map[string]dbCollection{}, lock: lock, } if primary { db.kv = kvstore.NewPrimary(root) } else { db.kv = kvstore.NewSecondary(root, db.onStore, db.onDelete) } return db } func (db *Database) Start() { wg := sync.WaitGroup{} for _, c := range db.collections { wg.Add(1) go func(c dbCollection) { defer wg.Done() c.loadData() }(c) } wg.Wait() } func (db *Database) MaxSeqNum() uint64 { return db.kv.MaxSeqNum() } func (db *Database) Close() { if db.kv != nil { db.kv.Close() db.kv = nil } if db.lock != nil { db.lock.Close() db.lock = nil } } // ---------------------------------------------------------------------------- func (db *Database) onStore(collection string, id uint64, data []byte) { c, ok := db.collections[collection] if ok { c.onStore(id, data) } } func (db *Database) onDelete(collection string, id uint64) { c, ok := db.collections[collection] if ok { c.onDelete(id) } } // ---------------------------------------------------------------------------- func (db *Database) SyncSend(conn net.Conn) { db.kv.SyncSend(conn) } func (db *Database) SyncRecv(conn net.Conn) { db.kv.SyncRecv(conn) }