store += append
[epoint] / store / store.go
index 48614f2..b05c79e 100644 (file)
@@ -1,29 +1,26 @@
 package store
 
 // persistent key-value store
-// TODO: thread safety, persistence, efficient update and query, incremental backup
+// multiple key-value store can be managed by a single db connection
+// each store has a name, before usage the name of the store must be
+// ensured to exist
+//
+// TODO: this is a toy implementation
 
 import (
-       "fmt"
        "os"
        "path/filepath"
        "io/ioutil"
-       "sync"
 )
 
 
 type Conn struct {
-       name string
        path string
-       mutex sync.RWMutex
-       memstore map[string][]byte
 }
 
-func Open(name string) (c *Conn, err error) {
+func Open(root string) (c *Conn, err error) {
        c = new(Conn)
-       c.memstore = make(map[string][]byte)
-       c.name = name
-       c.path, err = filepath.Abs(name)
+       c.path, err = filepath.Abs(root)
        if err != nil {
                return
        }
@@ -31,49 +28,40 @@ func Open(name string) (c *Conn, err error) {
        if err != nil {
                return
        }
-       err = filepath.Walk(c.path, func(path string, info *os.FileInfo, err error) error {
-               if info.IsDirectory() {
-                       if info.Name == c.name {
-                               return nil
-                       }
-                       return filepath.SkipDir
-               }
-               if err != nil {
-                       return err
-               }
-               k := info.Name
-               v, err := ioutil.ReadFile(filepath.Join(c.path, k))
-               if err != nil {
-                       return err
-               }
-               c.memstore[k] = v
-               return nil
-       })
        return
 }
 
-func (c *Conn) Get(k string) (v []byte, err error) {
-       c.mutex.RLock()
-       defer c.mutex.RUnlock()
-       v, ok := c.memstore[k]
-       if !ok {
-               err = fmt.Errorf("key not found")
-       }
-       return
+func (c *Conn) Get(name, k string) (v []byte, err error) {
+       return ioutil.ReadFile(filepath.Join(c.path, name, k))
+}
+
+func (c *Conn) Ensure(name string) (err error) {
+       return os.MkdirAll(filepath.Join(c.path, name), 0755)
 }
 
-func (c *Conn) Set(k string, v []byte) (err error) {
-       c.mutex.Lock()
-       defer c.mutex.Unlock()
-       f, err := os.Create(filepath.Join(c.path, k))
+func (c *Conn) Set(name, k string, v []byte) (err error) {
+       fn := filepath.Join(c.path, name, k)
+       f, err := os.OpenFile(fn+".tmp", os.O_CREATE|os.O_TRUNC|os.O_WRONLY|os.O_SYNC, 0666)
        if err != nil {
                return
        }
+       defer f.Close()
        _, err = f.Write(v)
        if err != nil {
                return
        }
-       c.memstore[k] = v
+       err = os.Rename(fn+".tmp", fn)
+       return
+}
+
+func (c *Conn) Append(name, k string, v []byte) (err error) {
+       fn := filepath.Join(c.path, name, k)
+       f, err := os.OpenFile(fn, os.O_CREATE|os.O_APPEND|os.O_WRONLY|os.O_SYNC, 0666)
+       if err != nil {
+               return
+       }
+       defer f.Close()
+       _, err = f.Write(v)
        return
 }