blob: 79b110161974f236a1fc5b418e70698080ce3262 [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package vsync
// Helpful wrappers to a persistent key/value (K/V) DB used by Veyron Sync.
// The current underlying DB is an in-memory map.
import (
"bytes"
"fmt"
"sort"
"v.io/v23/vom"
)
var memStore map[string]*kvdb
type kvdb struct {
tables map[string]*kvtable
}
type kvtable struct {
data map[string][]byte
}
// kvdbOpen opens or creates a K/V DB for the given filename and table names
// within the DB. It returns the DB handler and handlers for each table.
func kvdbOpen(filename string, tables []string) (*kvdb, []*kvtable, error) {
if memStore == nil {
memStore = make(map[string]*kvdb)
}
db := memStore[filename]
if db == nil {
db = &kvdb{tables: make(map[string]*kvtable)}
memStore[filename] = db
}
tbls := make([]*kvtable, len(tables))
for i, table := range tables {
t := db.tables[table]
if t == nil {
t = &kvtable{data: make(map[string][]byte)}
db.tables[table] = t
}
tbls[i] = t
}
return db, tbls, nil
}
// close closes the given K/V DB.
func (db *kvdb) close() {
}
// flush flushes the given K/V DB to disk.
func (db *kvdb) flush() {
}
// set stores (or overwrites) the given key/value pair in the DB table.
func (t *kvtable) set(key string, value interface{}) error {
var val bytes.Buffer
if err := vom.NewEncoder(&val).Encode(value); err != nil {
return err
}
t.data[key] = val.Bytes()
return nil
}
// create stores the given key/value pair in the DB table only if
// the key does not already exist. Otherwise it returns an error.
func (t *kvtable) create(key string, value interface{}) error {
if t.hasKey(key) {
return fmt.Errorf("key %s exists", key)
}
return t.set(key, value)
}
// update stores the given key/value pair in the DB table only if
// the key already exists. Otherwise it returns an error.
func (t *kvtable) update(key string, value interface{}) error {
if !t.hasKey(key) {
return fmt.Errorf("key %s does not exist", key)
}
return t.set(key, value)
}
// get retrieves the value of a key from the DB table.
func (t *kvtable) get(key string, value interface{}) error {
val := t.data[key]
if val == nil {
return fmt.Errorf("entry %s not found in the K/V DB table", key)
}
return vom.NewDecoder(bytes.NewBuffer(val)).Decode(value)
}
// del deletes the entry in the DB table given its key.
func (t *kvtable) del(key string) error {
delete(t.data, key)
return nil
}
// hasKey returns true if the given key exists in the DB table.
func (t *kvtable) hasKey(key string) bool {
val, ok := t.data[key]
return ok && val != nil
}
// keyIter iterates over all keys in a DB table invoking the given callback
// function for each one. The key iterator callback is passed the item key.
func (t *kvtable) keyIter(keyIterCB func(key string)) error {
keys := make([]string, 0, len(t.data))
for k := range t.data {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
keyIterCB(k)
}
return nil
}
// getNumKeys returns the number of keys (entries) in the DB table.
func (t *kvtable) getNumKeys() uint64 {
return uint64(len(t.data))
}