kunt

golang IRC bot
git clone git://git.2f30.org/kunt.git
Log | Files | Refs | LICENSE

commit 80f5a620c451f25842d994ba2b0a474c7728b5b1
parent a01240a6834260d743ad092573590de66d375fd6
Author: sin <sin@2f30.org>
Date:   Sat Apr 27 17:45:26 +0100

rename fsdb to mapfs

Diffstat:
src/fsdb/TODO | 1-
src/fsdb/fsdb.go | 223-------------------------------------------------------------------------------
src/kunt/kunt.go | 10+++++-----
src/mapfs/TODO | 1+
src/mapfs/mapfs.go | 223+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 229 insertions(+), 229 deletions(-)
diff --git a/src/fsdb/TODO b/src/fsdb/TODO @@ -1 +0,0 @@ -Add iterator interface (with a callback function or similar) diff --git a/src/fsdb/fsdb.go b/src/fsdb/fsdb.go @@ -1,223 +0,0 @@ -// Simple filesystem DB -package fsdb - -import ( - "errors" - "fmt" - "io/ioutil" - "math/rand" - "os" - "path" - "path/filepath" - "strconv" - "sync" -) - -type Fsdb struct { - 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]fsdbVal), - } -} - -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 nil, err - } - return b, err -} - -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 %s db", - path, d.name) - } - err = ioutil.WriteFile(path, buf, 0644) - if err != nil { - return err - } - return nil -} - -// 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 - } - d.dbMap[k] = fsdbVal{false, v.data} - fmt.Printf("Synced entry (%d, %v)\n", - k, v.data) - } - } - 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 { - dirty := "" - if v.dirty { - dirty = "yes" - } else { - dirty = "no" - } - s += fmt.Sprintf("k: %d - dirty: %s\n", - k, dirty) - } - return s -} - -// Mark all entries as synced but do not actually write them out to disk -func (d *Fsdb) virtSync() { - d.lock.Lock() - defer d.lock.Unlock() - for k, v := range d.dbMap { - d.dbMap[k] = fsdbVal{false, v.data} - } -} - -// 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 { - return err - } - b, err := d.fsRead(i) - if err != nil { - return err - } - if d.Dup(b) { - return fmt.Errorf("Duplicate entry: %s", b) - } - err = d.Put(i, b) - if err != nil { - return err - } - return nil - } - err = filepath.Walk(d.path, walkFunc) - if err == nil { - d.virtSync() - } - return err -} - -// Check if `buf' already exists in the DB -// Expects `d.lock' to be held by caller -func (d *Fsdb) Dup(buf []byte) bool { - d.lock.Lock() - defer d.lock.Unlock() - for _, v := range d.dbMap { - if string(v.data) == string(buf) { - return true - } - } - return false -} - -func (d *Fsdb) Put(key int, buf []byte) error { - d.lock.Lock() - defer d.lock.Unlock() - if key < 0 { - return fmt.Errorf("Invalid key: %d", key) - } - _, ok := d.dbMap[key] - if ok { - return fmt.Errorf("Key %d already in use", key) - } - d.dbMap[key] = fsdbVal{true, buf} - return nil -} - -// Append buf into the DB -func (d *Fsdb) Append(buf []byte) (int, error) { - d.lock.Lock() - defer d.lock.Unlock() - d.dbMap[len(d.dbMap)] = 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") - } - val, ok := d.dbMap[key] - if !ok { - return nil, fmt.Errorf("No entry with key: %d", key) - } - return val.data, nil -} - -func (d *Fsdb) Rand() ([]byte, int) { - d.lock.Lock() - defer d.lock.Unlock() - idx := rand.Intn(len(d.dbMap)) - i := 0 - for k, _ := range d.dbMap { - if i == idx { - val := d.dbMap[k] - return val.data, k - } - i++ - } - return nil, -1 -} - -func (d *Fsdb) Empty() bool { - d.lock.Lock() - defer d.lock.Unlock() - if len(d.dbMap) == 0 { - return true - } - return false -} - -func (d *Fsdb) Len() int { - d.lock.Lock() - defer d.lock.Unlock() - return len(d.dbMap) -} diff --git a/src/kunt/kunt.go b/src/kunt/kunt.go @@ -4,11 +4,11 @@ import ( "bytes" "flag" "fmt" - "fsdb" "games" "io/ioutil" "irc" "log" + "mapfs" "math/rand" "net/http" "os" @@ -260,8 +260,8 @@ func cmdGame(msg irc.IrcMessage) { var sslon = flag.Bool("s", false, "SSL support") -var quoteDb *fsdb.Fsdb -var urlDb *fsdb.Fsdb +var quoteDb *mapfs.Mapfs +var urlDb *mapfs.Mapfs var kunt kuntCtx var geng games.GameEnger var botname string @@ -281,8 +281,8 @@ func main() { hostport := strings.Split(flag.Arg(0), ":") - quoteDb = fsdb.NewFsdb("Quotes", "db/quotes", "quote") - urlDb = fsdb.NewFsdb("Urls", "db/urls", "url") + quoteDb = mapfs.NewMapfs("Quotes", "db/quotes", "quote") + urlDb = mapfs.NewMapfs("Urls", "db/urls", "url") err := quoteDb.Load() if err != nil { diff --git a/src/mapfs/TODO b/src/mapfs/TODO @@ -0,0 +1 @@ +Add iterator interface (with a callback function or similar) diff --git a/src/mapfs/mapfs.go b/src/mapfs/mapfs.go @@ -0,0 +1,223 @@ +// Simple fs backed up dictionary implementation +package mapfs + +import ( + "errors" + "fmt" + "io/ioutil" + "math/rand" + "os" + "path" + "path/filepath" + "strconv" + "sync" +) + +type Mapfs struct { + name string + path string + prefix string + dict map[int]mapfsVal + lock sync.Mutex +} + +type mapfsVal struct { + dirty bool // Do we need to sync this entry to the disk? + data []byte // Actual raw data +} + +func NewMapfs(name string, path string, prefix string) *Mapfs { + return &Mapfs{ + name: name, + path: path, + prefix: prefix, + dict: make(map[int]mapfsVal), + } +} + +func (m *Mapfs) fsRead(key int) ([]byte, error) { + path := fmt.Sprintf("%s/%s%d.txt", m.path, m.prefix, key) + b, err := ioutil.ReadFile(path) + if err != nil { + return nil, err + } + return b, err +} + +func (m *Mapfs) fsWrite(key int, buf []byte) error { + path := fmt.Sprintf("%s/%s%d.txt", m.path, m.prefix, key) + _, err := os.Stat(path) + if err == nil { + return fmt.Errorf("Entry %s already exists in %s db", + path, m.name) + } + err = ioutil.WriteFile(path, buf, 0644) + if err != nil { + return err + } + return nil +} + +// Sync dirty entries to disk +func (m *Mapfs) Sync() error { + m.lock.Lock() + defer m.lock.Unlock() + for k, v := range m.dict { + if v.dirty { + err := m.fsWrite(k, v.data) + if err != nil { + return err + } + m.dict[k] = mapfsVal{false, v.data} + fmt.Printf("Synced entry (%d, %v)\n", + k, v.data) + } + } + return nil +} + +// Print map +func (m *Mapfs) String() string { + m.lock.Lock() + defer m.lock.Unlock() + s := fmt.Sprintf("*** %s MAP DUMP ***\n", m.name) + for k, v := range m.dict { + dirty := "" + if v.dirty { + dirty = "yes" + } else { + dirty = "no" + } + s += fmt.Sprintf("k: %d - dirty: %s\n", + k, dirty) + } + return s +} + +// Mark all entries as synced but do not actually write them out to disk +func (m *Mapfs) virtSync() { + m.lock.Lock() + defer m.lock.Unlock() + for k, v := range m.dict { + m.dict[k] = mapfsVal{false, v.data} + } +} + +// Load the map from disk +func (m *Mapfs) Load() error { + _, err := os.Stat(m.path) + if err != nil { + // Just create the db if it does not exist + return os.MkdirAll(m.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(m.prefix) : len(base)-len(ext)] + i, err := strconv.Atoi(entry) + if err != nil { + return err + } + b, err := m.fsRead(i) + if err != nil { + return err + } + if m.Dup(b) { + return fmt.Errorf("Duplicate entry: %s", b) + } + err = m.Put(i, b) + if err != nil { + return err + } + return nil + } + err = filepath.Walk(m.path, walkFunc) + if err == nil { + m.virtSync() + } + return err +} + +// Check if `buf' already exists in the map +func (m *Mapfs) Dup(buf []byte) bool { + m.lock.Lock() + defer m.lock.Unlock() + for _, v := range m.dict { + if string(v.data) == string(buf) { + return true + } + } + return false +} + +func (m *Mapfs) Put(key int, buf []byte) error { + m.lock.Lock() + defer m.lock.Unlock() + if key < 0 { + return fmt.Errorf("Invalid key: %d", key) + } + _, ok := m.dict[key] + if ok { + return fmt.Errorf("Key %d already in use", key) + } + m.dict[key] = mapfsVal{true, buf} + return nil +} + +// Append buf to the map +func (m *Mapfs) Append(buf []byte) (int, error) { + m.lock.Lock() + defer m.lock.Unlock() + key := len(m.dict) + m.dict[key] = mapfsVal{true, buf} + return key, nil +} + +// Return the raw data based on the key +func (m *Mapfs) Get(key int) ([]byte, error) { + m.lock.Lock() + defer m.lock.Unlock() + if len(m.dict) == 0 { + return nil, errors.New("Empty map, can't fetch entry") + } + val, ok := m.dict[key] + if !ok { + return nil, fmt.Errorf("No entry with key: %d", key) + } + return val.data, nil +} + +func (m *Mapfs) Rand() ([]byte, int) { + m.lock.Lock() + defer m.lock.Unlock() + idx := rand.Intn(len(m.dict)) + i := 0 + for k, _ := range m.dict { + if i == idx { + val := m.dict[k] + return val.data, k + } + i++ + } + return nil, -1 +} + +func (m *Mapfs) Empty() bool { + m.lock.Lock() + defer m.lock.Unlock() + if len(m.dict) == 0 { + return true + } + return false +} + +func (m *Mapfs) Len() int { + m.lock.Lock() + defer m.lock.Unlock() + return len(m.dict) +}