diff options
author | Marc Pervaz Boocha <marcpervaz@qburst.com> | 2025-02-27 18:22:35 +0530 |
---|---|---|
committer | Marc Pervaz Boocha <marcpervaz@qburst.com> | 2025-02-27 18:22:35 +0530 |
commit | 7fe79f49b03fa7f6124a639d4b229e432ac3c840 (patch) | |
tree | 00abba4013c679e7c642e23a4bc9d7740841ba14 | |
parent | Added Memorize and UpdateInPlace (diff) | |
download | cache-7fe79f49b03fa7f6124a639d4b229e432ac3c840.tar cache-7fe79f49b03fa7f6124a639d4b229e432ac3c840.tar.gz cache-7fe79f49b03fa7f6124a639d4b229e432ac3c840.tar.bz2 cache-7fe79f49b03fa7f6124a639d4b229e432ac3c840.tar.lz cache-7fe79f49b03fa7f6124a639d4b229e432ac3c840.tar.xz cache-7fe79f49b03fa7f6124a639d4b229e432ac3c840.tar.zst cache-7fe79f49b03fa7f6124a639d4b229e432ac3c840.zip |
Resizing imporvements and typo fixes
-rw-r--r-- | conn.go | 6 | ||||
-rw-r--r-- | encoding.go | 6 | ||||
-rw-r--r-- | encoding_test.go | 12 | ||||
-rw-r--r-- | store.go | 64 | ||||
-rw-r--r-- | store_test.go | 4 |
5 files changed, 56 insertions, 36 deletions
@@ -311,15 +311,15 @@ func (h *DB[K, V]) UpdateInPlace(key K, processFunc func(V) (V, error), ttl time }, ttl) } -// Memoize attempts to retrieve a value from the cache. If the retrieval fails, +// Memorize attempts to retrieve a value from the cache. If the retrieval fails, // it sets the result of the factory function into the cache and returns that result. -func (h *DB[K, V]) Memoize(key K, factoryFunc func() (V, error), ttl time.Duration) (V, error) { +func (h *DB[K, V]) Memorize(key K, factoryFunc func() (V, error), ttl time.Duration) (V, error) { keyData, err := marshal(key) if err != nil { return zero[V](), err } - data, err := h.Store.Memoize(keyData, func() ([]byte, error) { + data, err := h.Store.Memorize(keyData, func() ([]byte, error) { value, err := factoryFunc() if err != nil { return nil, err diff --git a/encoding.go b/encoding.go index a4af699..343e345 100644 --- a/encoding.go +++ b/encoding.go @@ -197,9 +197,9 @@ func (d *decoder) DecodeStore(s *store) error { s.Length = length - k := 128 - for k < int(s.Length) { - k = k << 1 + k := initialBucketSize + for float64(s.Length)/float64(k) > float64(loadFactor) { + k = k * 2 } s.Bucket = make([]node, k) diff --git a/encoding_test.go b/encoding_test.go index 0f9245e..44104e4 100644 --- a/encoding_test.go +++ b/encoding_test.go @@ -248,10 +248,14 @@ func TestEncodeDecodeStrorage(t *testing.T) { { name: "Many Items", store: map[string]string{ - "Test1": "Test", - "Test2": "Test", - "Test3": "Test", - "Test4": "Test", + "1": "Test", + "2": "Test", + "3": "Test", + "4": "Test", + "5": "Test", + "6": "Test", + "7": "Test", + "8": "Test", }, policy: PolicyNone, maxCost: 0, @@ -8,15 +8,18 @@ import ( "github.com/marcthe12/cache/internal/pausedtimer" ) -const initialBucketSize uint64 = 8 +const ( + initialBucketSize uint64 = 8 + loadFactor float64 = 0.75 +) // node represents an entry in the cache with metadata for eviction and expiration. type node struct { Hash uint64 - Expiration time.Time - Access uint64 Key []byte Value []byte + Expiration time.Time + Access uint64 HashNext *node HashPrev *node @@ -24,6 +27,20 @@ type node struct { EvictPrev *node } +func (n *node) UnlinkHash() { + n.HashNext.HashPrev = n.HashPrev + n.HashPrev.HashNext = n.HashNext + n.HashNext = nil + n.HashPrev = nil +} + +func (n *node) UnlinkEvict() { + n.EvictNext.EvictPrev = n.EvictPrev + n.EvictPrev.EvictNext = n.EvictNext + n.EvictNext = nil + n.EvictPrev = nil +} + // IsValid checks if the node is still valid based on its expiration time. func (n *node) IsValid() bool { return n.Expiration.IsZero() || n.Expiration.After(time.Now()) @@ -38,6 +55,10 @@ func (n *node) TTL() time.Duration { } } +func (n *node) Cost() uint64 { + return uint64(len(n.Key) + len(n.Value)) +} + // store represents the in-memory cache with eviction policies and periodic tasks. type store struct { Bucket []node @@ -188,10 +209,10 @@ func (s *store) insert(key []byte, value []byte, ttl time.Duration) { idx, hash := lookupIdx(s, key) bucket := &s.Bucket[idx] - if float64(s.Length)/float64(len(s.Bucket)) > 0.75 { + if float64(s.Length)/float64(len(s.Bucket)) > float64(loadFactor) { s.Resize() // resize may invalidate pointer to bucket - _, idx, _ = s.lookup(key) + idx, _ = lookupIdx(s, key) bucket = &s.Bucket[idx] lazyInitBucket(bucket) } @@ -215,7 +236,7 @@ func (s *store) insert(key []byte, value []byte, ttl time.Duration) { s.Policy.OnInsert(v) - s.Cost = s.Cost + uint64(len(key)) + uint64(len(value)) + s.Cost = s.Cost + v.Cost() s.Length = s.Length + 1 } @@ -226,13 +247,14 @@ func (s *store) Set(key []byte, value []byte, ttl time.Duration) { v, _, _ := s.lookup(key) if v != nil { - s.Cost = s.Cost + uint64(len(value)) - uint64(len(v.Value)) + cost := v.Cost() v.Value = value if ttl != 0 { v.Expiration = time.Now().Add(ttl) } else { v.Expiration = zero[time.Time]() } + s.Cost = s.Cost + v.Cost() - cost s.Policy.OnUpdate(v) return } @@ -242,17 +264,10 @@ func (s *store) Set(key []byte, value []byte, ttl time.Duration) { // deleteNode removes a node from the store. func deleteNode(s *store, v *node) { - v.HashNext.HashPrev = v.HashPrev - v.HashPrev.HashNext = v.HashNext - v.HashNext = nil - v.HashPrev = nil - - v.EvictNext.EvictPrev = v.EvictPrev - v.EvictPrev.EvictNext = v.EvictNext - v.EvictNext = nil - v.EvictPrev = nil + v.UnlinkEvict() + v.UnlinkHash() - s.Cost = s.Cost - (uint64(len(v.Key)) + uint64(len(v.Value))) + s.Cost = s.Cost - v.Cost() s.Length = s.Length - 1 } @@ -287,18 +302,19 @@ func (s *store) UpdateInPlace(key []byte, processFunc func([]byte) ([]byte, erro return ErrKeyNotFound } - processedValue, err := processFunc(v.Value) + value, err := processFunc(v.Value) if err != nil { return err } - s.Cost = s.Cost + uint64(len(processedValue)) - uint64(len(v.Value)) - v.Value = processedValue + cost := v.Cost() + v.Value = value if ttl != 0 { v.Expiration = time.Now().Add(ttl) } else { v.Expiration = zero[time.Time]() } + s.Cost = s.Cost + v.Cost() - cost s.Policy.OnUpdate(v) return nil @@ -306,7 +322,7 @@ func (s *store) UpdateInPlace(key []byte, processFunc func([]byte) ([]byte, erro // Memorize attempts to retrieve a value from the store. If the retrieval fails, // it sets the result of the factory function into the store and returns that result. -func (s *store) Memorize(key []byte, factoryFunc func() ([]byte, error), ttl time.Duration) ([]byte, error) { +func (s *store) Memorize(key []byte, factory func() ([]byte, error), ttl time.Duration) ([]byte, error) { s.mu.Lock() defer s.mu.Unlock() @@ -316,11 +332,11 @@ func (s *store) Memorize(key []byte, factoryFunc func() ([]byte, error), ttl tim return v.Value, nil } - factoryValue, err := factoryFunc() + value, err := factory() if err != nil { return nil, err } - s.insert(key, factoryValue, ttl) - return factoryValue, nil + s.insert(key, value, ttl) + return value, nil } diff --git a/store_test.go b/store_test.go index e2c44e9..cf8e58e 100644 --- a/store_test.go +++ b/store_test.go @@ -229,7 +229,7 @@ func TestStoreMemoize(t *testing.T) { return []byte("Value"), nil } - got, err := store.Memoize([]byte("Key"), factoryFunc, 1*time.Hour) + got, err := store.Memorize([]byte("Key"), factoryFunc, 1*time.Hour) if err != nil { t.Fatalf("unexpected error: %v", err) } @@ -257,7 +257,7 @@ func TestStoreMemoize(t *testing.T) { return []byte("NewValue"), nil } - got, err := store.Memoize([]byte("Key"), factoryFunc, 1*time.Hour) + got, err := store.Memorize([]byte("Key"), factoryFunc, 1*time.Hour) if err != nil { t.Fatalf("unexpected error: %v", err) } |