commit f2b445f2b8681df1d52fc347702e7725a3491dcc
parent 152c9521a6ce27dd0603e74df4591c83f03074f0
Author: sin <sin@2f30.org>
Date: Fri, 26 Apr 2013 15:33:19 +0100
fsdb: Cleanup the code
Diffstat:
2 files changed, 109 insertions(+), 64 deletions(-)
diff --git a/src/fsdb/fsdb.go b/src/fsdb/fsdb.go
@@ -1,127 +1,172 @@
+// Simple filesystem DB
package fsdb
import (
"errors"
"fmt"
"io/ioutil"
- "log"
"math/rand"
"os"
"path"
"path/filepath"
"strconv"
- "strings"
"sync"
)
type Fsdb struct {
- name string
- path string
- prefix string
- dbMap map[int][]byte
- lastKey int
- lock sync.Mutex
+ name string
+ path string
+ prefix string
+ dbMap map[int]fsdbVal
+ lock sync.Mutex
+}
+
+type fsdbVal struct {
+ dirty bool // Do we need to sync this entry to the disk?
+ data []byte // Actual raw data
}
func NewFsdb(name string, path string, prefix string) *Fsdb {
return &Fsdb{
- name: name,
- path: path,
- prefix: prefix,
- dbMap: make(map[int][]byte),
- lastKey: -1,
+ name: name,
+ path: path,
+ prefix: prefix,
+ dbMap: make(map[int]fsdbVal),
}
}
-func (d *Fsdb) FsRead(quote int) ([]byte, error) {
- path := fmt.Sprintf("%s/%s%d.txt", d.path, d.prefix, quote)
+func (d *Fsdb) fsRead(key int) ([]byte, error) {
+ path := fmt.Sprintf("%s/%s%d.txt", d.path, d.prefix, key)
b, err := ioutil.ReadFile(path)
if err != nil {
- return b, err
+ return nil, err
}
return b, err
}
-func (d *Fsdb) FsWrite(quote int, buf []byte) error {
- path := fmt.Sprintf("%s/%s%d.txt", d.path, d.prefix, quote)
+func (d *Fsdb) fsWrite(key int, buf []byte) error {
+ path := fmt.Sprintf("%s/%s%d.txt", d.path, d.prefix, key)
_, err := os.Stat(path)
if err == nil {
- return fmt.Errorf("Entry %s already exists in fsdb\n",
- path)
+ return fmt.Errorf("Entry %s already exists in %s db",
+ path, d.name)
}
- s := string(buf)
- last := strings.Index(s, "\n")
- err = ioutil.WriteFile(path, buf[0:last+1], 0644)
+ err = ioutil.WriteFile(path, buf, 0644)
if err != nil {
return err
}
return nil
}
-func (d *Fsdb) Load() {
- err := filepath.Walk(d.path, func(p string, f os.FileInfo, err error) error {
- fi, err := os.Stat(p)
- if err != nil {
- log.Fatal(err)
+// Sync dirty entries to disk
+func (d *Fsdb) Sync() error {
+ d.lock.Lock()
+ defer d.lock.Unlock()
+ for k, v := range d.dbMap {
+ if v.dirty {
+ err := d.fsWrite(k, v.data)
+ if err != nil {
+ return err
+ }
+ fmt.Printf("Synced entry (%d, %v)\n",
+ k, v.data)
+ v.dirty = false
}
+ }
+ return nil
+}
+
+// Print DB
+func (d *Fsdb) String() string {
+ d.lock.Lock()
+ defer d.lock.Unlock()
+ s := fmt.Sprintf("*** %s DB DUMP ***\n", d.name)
+ for k, v := range d.dbMap {
+ s += fmt.Sprintf("k: %d -> v: %v\n",
+ k, v)
+ }
+ return s
+}
+
+// Load the DB from disk
+func (d *Fsdb) Load() error {
+ _, err := os.Stat(d.path)
+ if err != nil {
+ // Just create the db if it does not exist
+ return os.MkdirAll(d.path, 0755)
+ }
+ walkFunc := func(p string, fi os.FileInfo, err error) error {
if fi.IsDir() {
return nil
}
+ if err != nil {
+ return err
+ }
base, ext := path.Base(p), path.Ext(p)
entry := base[len(d.prefix) : len(base)-len(ext)]
i, err := strconv.Atoi(entry)
if err != nil {
- log.Fatal(err)
+ return err
}
- b, err := d.FsRead(i)
+ b, err := d.fsRead(i)
if err != nil {
- log.Fatal(err)
+ return err
}
- _, err = d.Put(i, b)
+ err = d.putIdx(i, b, false)
if err != nil {
- log.Fatal(err)
+ return err
}
return nil
- })
- if err != nil {
- log.Fatal(err)
}
+ return filepath.Walk(d.path, walkFunc)
}
-func (d *Fsdb) Put(key int, buf []byte) (int, error) {
- d.lock.Lock()
- defer d.lock.Unlock()
+// Check if `buf' already exists in the DB
+func (d *Fsdb) dup(buf []byte) bool {
for _, v := range d.dbMap {
- if string(v) == string(buf) {
- return -1, errors.New("Duplicate entry: " + string(buf))
+ if string(v.data) == string(buf) {
+ return true
}
}
- if key == -1 {
- d.lastKey++
- key = d.lastKey
- } else {
- if key > d.lastKey {
- d.lastKey = key
- }
+ return false
+}
+
+func (d *Fsdb) putIdx(key int, buf []byte, dirty bool) error {
+ d.lock.Lock()
+ defer d.lock.Unlock()
+ if key < 0 {
+ return fmt.Errorf("Invalid key: %d", key)
}
- if d.dbMap[key] != nil {
- log.Fatal("Duplicate entry in fsdb")
+ if d.dup(buf) {
+ return fmt.Errorf("Duplicate entry: %s", buf)
+ }
+ d.dbMap[key] = fsdbVal{dirty, buf}
+ return nil
+}
+
+// Append buf into the DB
+func (d *Fsdb) Append(buf []byte) (int, error) {
+ d.lock.Lock()
+ defer d.lock.Unlock()
+ if d.dup(buf) {
+ return -1, fmt.Errorf("Duplicate entry: %s", buf)
}
- d.dbMap[key] = buf
- return key, nil
+ d.dbMap[d.Len()] = fsdbVal{true, buf}
+ return -1, nil
}
+// Return the raw data based on the key
func (d *Fsdb) Get(key int) ([]byte, error) {
d.lock.Lock()
defer d.lock.Unlock()
if len(d.dbMap) == 0 {
return nil, errors.New("Empty DB, can't fetch entry")
}
- buf := d.dbMap[key]
- if buf == nil {
- log.Fatal("Fetching nil entry from fsdb")
+ val, ok := d.dbMap[key]
+ if !ok {
+ return nil, fmt.Errorf("No entry with key: %d", key)
}
- return buf, nil
+ return val.data, nil
}
func (d *Fsdb) Rand() ([]byte, int) {
@@ -132,8 +177,8 @@ func (d *Fsdb) Rand() ([]byte, int) {
i := 0
for k, _ := range d.dbMap {
if i == idx {
- buf := d.dbMap[k]
- return buf, k
+ val := d.dbMap[k]
+ return val.data, k
}
i++
}
diff --git a/src/kunt/kunt.go b/src/kunt/kunt.go
@@ -120,12 +120,12 @@ func cmdAddQuote(msg irc.IrcMessage) {
s = strings.TrimSpace(s)
s += "\n"
buf := []byte(s)
- quote, err := quoteDb.Put(-1, buf)
+ _, err := quoteDb.Append(buf)
if err != nil {
kunt.ircCtx.SendPrivmsg(msg.Params[0], err.Error())
return
}
- err = quoteDb.FsWrite(quote, buf)
+ err = quoteDb.Sync()
if err != nil {
log.Fatal(err)
}
@@ -165,12 +165,12 @@ func cmdAddUrl(msg irc.IrcMessage) {
s = strings.TrimSpace(s)
s += "\n"
buf := []byte(s)
- url, err := urlDb.Put(-1, buf)
+ _, err := urlDb.Append(buf)
if err != nil {
kunt.ircCtx.SendPrivmsg(msg.Params[0], err.Error())
return
}
- err = urlDb.FsWrite(url, buf)
+ err = urlDb.Sync()
if err != nil {
log.Fatal(err)
}
@@ -271,8 +271,8 @@ func main() {
hostport := strings.Split(flag.Arg(0), ":")
- quoteDb = fsdb.NewFsdb("Quote DB", "db/quotes", "quote")
- urlDb = fsdb.NewFsdb("Url DB", "db/urls", "url")
+ quoteDb = fsdb.NewFsdb("Quotes", "db/quotes", "quote")
+ urlDb = fsdb.NewFsdb("Urls", "db/urls", "url")
quoteDb.Load()
urlDb.Load()