diff options
Diffstat (limited to 'kv')
-rw-r--r-- | kv/kv.go | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/kv/kv.go b/kv/kv.go new file mode 100644 index 0000000..2cfcd60 --- /dev/null +++ b/kv/kv.go @@ -0,0 +1,92 @@ +package kv + +import ( + "errors" + "io/ioutil" + "os" + "path/filepath" + "strings" + "sync" +) + +var ( + errInvalidKey = errors.New("invalid key") + errNoSuchKey = errors.New("no such key") +) + +type Database struct { + data map[string][]byte + basedir string + m sync.RWMutex +} + +func NewDatabse(basedir string) (db *Database, err error) { + err = os.Mkdir(basedir, 0755) + if err != nil && !os.IsExist(err) { + return + } + + return &Database{ + data: make(map[string][]byte), + basedir: basedir, + }, nil +} + +func (db *Database) Set(key string, val []byte) (err error) { + if len(key) < 1 { + return errInvalidKey + } + + db.m.Lock() + defer func() { + if err != nil { + delete(db.data, key) + } + db.m.Unlock() + }() + + db.data[key] = val + + err = ioutil.WriteFile(filepath.Join(db.basedir, key), val, 0644) + + return +} + +func (db *Database) Get(key string) (val []byte, err error) { + if len(key) < 1 { + return nil, errInvalidKey + } + + db.m.RLock() + defer db.m.RUnlock() + + data, ok := db.data[key] + if !ok { + data, err = ioutil.ReadFile(filepath.Join(db.basedir, key)) + if err != nil { + err = errNoSuchKey + return nil, err + } + + db.data[key] = data + } + + val = make([]byte, len(data)) + copy(val, data) + + return +} + +func (db *Database) Remove(key string) { + if len(key) < 1 || strings.ContainsRune(key, os.PathSeparator) { + return + } + + db.m.Lock() + defer db.m.Unlock() + + delete(db.data, key) + os.Remove(filepath.Join(db.basedir, key)) + + return +} |