diff options
author | Marc Pervaz Boocha <marcpervaz@qburst.com> | 2025-02-14 18:06:02 +0530 |
---|---|---|
committer | Marc Pervaz Boocha <marcpervaz@qburst.com> | 2025-02-14 18:06:02 +0530 |
commit | 0b6df1549e53ca4747b070043ebc4a41c5a5f47c (patch) | |
tree | 203b46f596473e10dfeb9157c8cb4763d29e2d76 /conn.go | |
download | cache-0b6df1549e53ca4747b070043ebc4a41c5a5f47c.tar cache-0b6df1549e53ca4747b070043ebc4a41c5a5f47c.tar.gz cache-0b6df1549e53ca4747b070043ebc4a41c5a5f47c.tar.bz2 cache-0b6df1549e53ca4747b070043ebc4a41c5a5f47c.tar.lz cache-0b6df1549e53ca4747b070043ebc4a41c5a5f47c.tar.xz cache-0b6df1549e53ca4747b070043ebc4a41c5a5f47c.tar.zst cache-0b6df1549e53ca4747b070043ebc4a41c5a5f47c.zip |
First Commit
Diffstat (limited to '')
-rw-r--r-- | conn.go | 138 |
1 files changed, 138 insertions, 0 deletions
@@ -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 +} |