diff options
Diffstat (limited to 'kv.go')
-rw-r--r-- | kv.go | 93 |
1 files changed, 93 insertions, 0 deletions
@@ -0,0 +1,93 @@ +package kv + +import ( + "errors" + "io/ioutil" + "os" + "path/filepath" + "strings" + "sync" +) + +var ( + ErrInvalidKey = errors.New("kv: invalid key") + ErrNoSuchKey = errors.New("kv: no such key") +) + +type DB struct { + cache map[string][]byte + basedir string + m sync.RWMutex +} + +func NewDB(basedir string) (db *DB, err error) { + err = os.Mkdir(basedir, 0755) + if err != nil && !os.IsExist(err) { + return + } + + return &DB{ + cache: make(map[string][]byte), + basedir: basedir, + }, nil +} + +func (db *DB) Set(key string, val []byte) (err error) { + if len(key) < 1 || strings.ContainsRune(key, os.PathSeparator) { + return ErrInvalidKey + } + db.m.Lock() + defer db.m.Unlock() + + err = ioutil.WriteFile(filepath.Join(db.basedir, key), val, 0644) + if err != nil { + return + } + + db.cache[key] = val + return +} + +func (db *DB) Get(key string) (val []byte, err error) { + if len(key) < 1 || strings.ContainsRune(key, os.PathSeparator) { + return nil, ErrInvalidKey + } + db.m.Lock() + defer db.m.Unlock() + + data, ok := db.cache[key] + if !ok { + data, err = ioutil.ReadFile(filepath.Join(db.basedir, key)) + if err != nil { + if os.IsNotExist(err) { + err = ErrNoSuchKey + } + return nil, err + } + + db.cache[key] = data + } + + val = make([]byte, len(data)) + copy(val, data) + return +} + +func (db *DB) Remove(key string) (err error) { + if len(key) < 1 || strings.ContainsRune(key, os.PathSeparator) { + return ErrInvalidKey + } + db.m.Lock() + defer db.m.Unlock() + + err = os.Remove(filepath.Join(db.basedir, key)) + if err != nil { + if os.IsNotExist(err) { + err = ErrNoSuchKey + } + return + } + + delete(db.cache, key) + return +} |