From 1aaad66233c95e9e188adb7f1eb152bc3fe1370d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Schw=C3=B6rer?= Date: Thu, 22 Dec 2022 10:06:25 +0100 Subject: [PATCH] v0.0.42 --- dataext/lruMap.go | 38 ++++++++++++++++++-------------------- dataext/lruMap_test.go | 31 +++++++++---------------------- sq/database.go | 5 +++++ 3 files changed, 32 insertions(+), 42 deletions(-) diff --git a/dataext/lruMap.go b/dataext/lruMap.go index 2f267e1..0016466 100644 --- a/dataext/lruMap.go +++ b/dataext/lruMap.go @@ -19,40 +19,38 @@ import ( // There are also a bunch of unit tests to ensure that the cache is always in a consistent state // -type LRUData interface{} - -type LRUMap struct { +type LRUMap[TData any] struct { maxsize int lock sync.Mutex - cache map[string]*cacheNode + cache map[string]*cacheNode[TData] - lfuHead *cacheNode - lfuTail *cacheNode + lfuHead *cacheNode[TData] + lfuTail *cacheNode[TData] } -type cacheNode struct { +type cacheNode[TData any] struct { key string - data LRUData - parent *cacheNode - child *cacheNode + data TData + parent *cacheNode[TData] + child *cacheNode[TData] } -func NewLRUMap(size int) *LRUMap { +func NewLRUMap[TData any](size int) *LRUMap[TData] { if size <= 2 && size != 0 { panic("Size must be > 2 (or 0)") } - return &LRUMap{ + return &LRUMap[TData]{ maxsize: size, lock: sync.Mutex{}, - cache: make(map[string]*cacheNode, size+1), + cache: make(map[string]*cacheNode[TData], size+1), lfuHead: nil, lfuTail: nil, } } -func (c *LRUMap) Put(key string, value LRUData) { +func (c *LRUMap[TData]) Put(key string, value TData) { if c.maxsize == 0 { return // cache disabled } @@ -70,7 +68,7 @@ func (c *LRUMap) Put(key string, value LRUData) { } // key does not exist: insert into map and add to top of LFU - node = &cacheNode{ + node = &cacheNode[TData]{ key: key, data: value, parent: nil, @@ -95,9 +93,9 @@ func (c *LRUMap) Put(key string, value LRUData) { } } -func (c *LRUMap) TryGet(key string) (LRUData, bool) { +func (c *LRUMap[TData]) TryGet(key string) (TData, bool) { if c.maxsize == 0 { - return nil, false // cache disabled + return *new(TData), false // cache disabled } c.lock.Lock() @@ -105,13 +103,13 @@ func (c *LRUMap) TryGet(key string) (LRUData, bool) { val, ok := c.cache[key] if !ok { - return nil, false + return *new(TData), false } c.moveNodeToTop(val) return val.data, ok } -func (c *LRUMap) moveNodeToTop(node *cacheNode) { +func (c *LRUMap[TData]) moveNodeToTop(node *cacheNode[TData]) { // (only called in critical section !) if c.lfuHead == node { // fast case @@ -144,7 +142,7 @@ func (c *LRUMap) moveNodeToTop(node *cacheNode) { } } -func (c *LRUMap) Size() int { +func (c *LRUMap[TData]) Size() int { c.lock.Lock() defer c.lock.Unlock() return len(c.cache) diff --git a/dataext/lruMap_test.go b/dataext/lruMap_test.go index 4a439cc..1b50f77 100644 --- a/dataext/lruMap_test.go +++ b/dataext/lruMap_test.go @@ -12,7 +12,7 @@ func init() { } func TestResultCache1(t *testing.T) { - cache := NewLRUMap(8) + cache := NewLRUMap[string](8) verifyLRUList(cache, t) key := randomKey() @@ -39,7 +39,7 @@ func TestResultCache1(t *testing.T) { if !ok { t.Errorf("cache TryGet returned no value") } - if !eq(cacheval, val) { + if cacheval != val { t.Errorf("cache TryGet returned different value (%+v <> %+v)", cacheval, val) } @@ -50,7 +50,7 @@ func TestResultCache1(t *testing.T) { } func TestResultCache2(t *testing.T) { - cache := NewLRUMap(8) + cache := NewLRUMap[string](8) verifyLRUList(cache, t) key1 := "key1" @@ -150,7 +150,7 @@ func TestResultCache2(t *testing.T) { } func TestResultCache3(t *testing.T) { - cache := NewLRUMap(8) + cache := NewLRUMap[string](8) verifyLRUList(cache, t) key1 := "key1" @@ -160,20 +160,20 @@ func TestResultCache3(t *testing.T) { cache.Put(key1, val1) verifyLRUList(cache, t) - if val, ok := cache.TryGet(key1); !ok || !eq(val, val1) { + if val, ok := cache.TryGet(key1); !ok || val != val1 { t.Errorf("Value in cache should be [val1]") } cache.Put(key1, val2) verifyLRUList(cache, t) - if val, ok := cache.TryGet(key1); !ok || !eq(val, val2) { + if val, ok := cache.TryGet(key1); !ok || val != val2 { t.Errorf("Value in cache should be [val2]") } } // does a basic consistency check over the internal cache representation -func verifyLRUList(cache *LRUMap, t *testing.T) { +func verifyLRUList[TData any](cache *LRUMap[TData], t *testing.T) { size := 0 tailFound := false @@ -250,23 +250,10 @@ func randomKey() string { return strconv.FormatInt(rand.Int63(), 16) } -func randomVal() LRUData { +func randomVal() string { v, err := langext.NewHexUUID() if err != nil { panic(err) } - return &v -} - -func eq(a LRUData, b LRUData) bool { - v1, ok1 := a.(*string) - v2, ok2 := b.(*string) - if ok1 && ok2 { - if v1 == nil || v2 == nil { - return false - } - return v1 == v2 - } - - return false + return v } diff --git a/sq/database.go b/sq/database.go index 830368d..3cefdea 100644 --- a/sq/database.go +++ b/sq/database.go @@ -13,6 +13,7 @@ type DB interface { Ping(ctx context.Context) error BeginTransaction(ctx context.Context, iso sql.IsolationLevel) (Tx, error) AddListener(listener Listener) + Exit() error } type database struct { @@ -121,3 +122,7 @@ func (db *database) BeginTransaction(ctx context.Context, iso sql.IsolationLevel return NewTransaction(xtx, txid, db.lstr), nil } + +func (db *database) Exit() error { + return db.db.Close() +}