aboutsummaryrefslogtreecommitdiffstats
path: root/conn.go
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--conn.go138
1 files changed, 138 insertions, 0 deletions
diff --git a/conn.go b/conn.go
new file mode 100644
index 0000000..d88744c
--- /dev/null
+++ b/conn.go
@@ -0,0 +1,138 @@
+package cache
+
+import (
+ "errors"
+ "os"
+ "sync"
+ "time"
+
+ "github.com/vmihailenco/msgpack"
+)
+
+type DB[K any, V any] struct {
+ file *os.File
+ Store Store
+ stop chan struct{}
+ wg sync.WaitGroup
+}
+
+func OpenFile[K any, V any](filename string) (*DB[K, V], error) {
+ ret := &DB[K, V]{}
+ file, err := os.OpenFile(filename, os.O_RDWR, 0)
+ if errors.Is(err, os.ErrNotExist) {
+ file, err := os.Create(filename)
+ if err != nil {
+ return nil, err
+ }
+ ret.file = file
+ ret.SetStratergy(StrategyNone)
+ ret.Clear()
+ ret.Flush()
+ } else if err == nil {
+ ret.Clear()
+ ret.file = file
+ ret.Store.LoadSnapshot(ret.file)
+ } else {
+ return nil, err
+ }
+ ret.wg.Add(1)
+ go ret.backgroundWorker()
+ return ret, nil
+}
+
+func OpenMem[K any, V any]() *DB[K, V] {
+ ret := &DB[K, V]{}
+ ret.SetStratergy(StrategyNone)
+ ret.Clear()
+ return ret
+}
+
+func (d *DB[K, V]) SetStratergy(e EvictionPolicy) error {
+ strategy, err := e.ToStratergy(&d.Store.evict)
+ if err != nil {
+ return err
+ }
+ d.Store.strategy = strategy
+ return nil
+}
+
+func (d *DB[K, V]) SetMaxCost(e EvictionPolicy) {
+ d.Store.max_cost = d.Store.max_cost
+}
+
+func (d *DB[K, V]) backgroundWorker() {
+ defer d.wg.Done()
+ for {
+ select {
+ case <-d.stop:
+ return
+ // TODO: Do house keeping
+ }
+ }
+}
+
+func (d *DB[K, V]) Close() {
+ close(d.stop)
+ d.wg.Wait()
+ d.Flush()
+ d.Clear()
+ if d.file != nil {
+ d.file.Close()
+ }
+}
+
+func (d *DB[K, V]) Flush() error {
+ if d.file != nil {
+ return d.Store.Snapshot(d.file)
+ }
+ return nil
+}
+
+func (d *DB[K, V]) Clear() {
+ d.Store.Clear()
+}
+
+var ErrKeyNotFound = errors.New("key not found")
+
+func (h *DB[K, V]) Get(key K) (V, time.Duration, error) {
+ keyData, err := msgpack.Marshal(key)
+ if err != nil {
+ return zero[V](), 0, err
+ }
+
+ v, ttl, ok := h.Store.Get(keyData)
+ if !ok {
+ return zero[V](), 0, ErrKeyNotFound
+ }
+
+ var ret V
+ if err = msgpack.Unmarshal(v, &ret); err != nil {
+ return zero[V](), 0, err
+ }
+ return ret, ttl, err
+}
+
+func (h *DB[K, V]) Set(key K, value V, ttl time.Duration) error {
+ keyData, err := msgpack.Marshal(key)
+ if err != nil {
+ return err
+ }
+ valueData, err := msgpack.Marshal(value)
+ if err != nil {
+ return err
+ }
+ h.Store.Set(keyData, valueData, ttl)
+ return nil
+}
+
+func (h *DB[K, V]) Delete(key K) error {
+ keyData, err := msgpack.Marshal(key)
+ if err != nil {
+ return err
+ }
+ ok := h.Store.Delete(keyData)
+ if !ok {
+ return ErrKeyNotFound
+ }
+ return nil
+}