From 953a32b04c4680f15213bdae2936491c2c150f2c Mon Sep 17 00:00:00 2001 From: Code0987 <1825861+Code0987@users.noreply.github.com> Date: Wed, 2 Sep 2026 13:33:27 +0000 Subject: [PATCH] refactor: extract ModeBitmap into its own files Move store Bitmap off memory.go and split engine Bitmap into public API, owner apply, and cluster hops. No contract change. --- docs/design/2026-09-02-refactor-bitmap.md | 38 +++++ docs/design/README.md | 1 + pkg/engine/bitmap.go | 104 +------------ pkg/engine/bitmap_apply.go | 64 ++++++++ pkg/engine/bitmap_cluster.go | 65 ++++++++ pkg/store/bitmap.go | 174 ++++++++++++++++++++++ pkg/store/memory.go | 159 -------------------- 7 files changed, 343 insertions(+), 262 deletions(-) create mode 100644 docs/design/2026-09-02-refactor-bitmap.md create mode 100644 pkg/engine/bitmap_apply.go create mode 100644 pkg/engine/bitmap_cluster.go create mode 100644 pkg/store/bitmap.go diff --git a/docs/design/2026-09-02-refactor-bitmap.md b/docs/design/2026-09-02-refactor-bitmap.md new file mode 100644 index 0000000..7d988ac --- /dev/null +++ b/docs/design/2026-09-02-refactor-bitmap.md @@ -0,0 +1,38 @@ +# Refactor ModeBitmap layout (no contract change) + +**Status:** approved (chat: continue after HLL) +**Branch:** `feat/refactor-bitmap` +**Date:** 2026-09-02 + +## Problem + +Bitmap store methods still live in `pkg/store/memory.go`. Engine Bitmap is one ~250-line file mixing public verbs, owner apply, and cluster hops. + +## Non-goals + +- No API / proto / flag / version / fan-out / hintID change +- No `bitmapx` algorithm change +- Not extracting other modes (HLL is a separate PR) + +## Contract + +Unchanged: `BitSet` / `BitGet` / `BitCount` / `BitPos` / `Delete(name)`, `FlagBitmap` + inbox `FlagBitmapSet`, snapshot fan-out, version under store mutex, present-bit, empty-until-delete. + +## Approach + +Same file layout as HLL / TopK / CMS: + +| Before | After | +|--------|--------| +| `pkg/store/memory.go` B* | `pkg/store/bitmap.go` | +| `pkg/engine/bitmap.go` (all) | `bitmap.go` public verbs; `bitmap_apply.go` owner write; `bitmap_cluster.go` inbox/fan-out/GetOrLoad | + +Rejected: rewrite bit packing; split `bitmapx` (150 lines is one file). + +## Tests (already exist; keep them) + +Existing `pkg/bitmapx`, `pkg/store` bitmap, `pkg/engine` bitmap unit + cluster + hint-after-down. + +## Bench risk + +No new Get/Peek logic. Local `BenchmarkEngineGetHit` / `BenchmarkStoreGetHit` allocs/op must stay 15 / 2. diff --git a/docs/design/README.md b/docs/design/README.md index 7275235..b6a72d2 100644 --- a/docs/design/README.md +++ b/docs/design/README.md @@ -22,6 +22,7 @@ Do not implement from a draft. | [2026-08-25-mode-hll.md](./2026-08-25-mode-hll.md) | `ModeHLL` | | [2026-08-31-mode-topk.md](./2026-08-31-mode-topk.md) | `ModeTopK` | | [2026-09-01-mode-cms.md](./2026-09-01-mode-cms.md) | `ModeCMS` | +| [2026-09-02-refactor-bitmap.md](./2026-09-02-refactor-bitmap.md) | ModeBitmap file layout (no contract) | | [2026-08-25-list-counter-version.md](./2026-08-25-list-counter-version.md) | List/Counter snapshot version | | [2026-08-13-unify-grpc-error-map.md](./2026-08-13-unify-grpc-error-map.md) | grpcmap | diff --git a/pkg/engine/bitmap.go b/pkg/engine/bitmap.go index 8e946b2..344a4a3 100644 --- a/pkg/engine/bitmap.go +++ b/pkg/engine/bitmap.go @@ -6,10 +6,10 @@ import ( "github.com/Code0987/supercache/pkg/bitmapx" "github.com/Code0987/supercache/pkg/keyspace" - "github.com/Code0987/supercache/pkg/store" ) // BitSet writes a bit on a ModeBitmap (Redis SETBIT). ACK-only. +// Non-owners forward an inbox FlagBitmapSet; the owner applies and fans a snapshot. func (e *Engine) BitSet(ctx context.Context, keyspaceName, name string, offset uint64, bit bool) error { if err := ctx.Err(); err != nil { return err @@ -144,105 +144,3 @@ func (e *Engine) bitmapNeed(ks *ksRuntime, offset uint64) error { } return nil } - -func (e *Engine) bMutViaOwner(ctx context.Context, ks *ksRuntime, name string, value []byte) error { - c := e.clusterSnapshot() - owner, _ := c.Ring.Owner(name) - ent := store.Entry{Value: value, Flags: store.FlagBitmapSet, Version: 1} - pctx, cancel := e.peerCtx(ctx, ks) - defer cancel() - applied, err := c.Transport.ApplyPut(pctx, owner.Addr, ks.cfg.Name, name, ent, c.Ring.Generation()) - if err != nil { - return err - } - if !applied { - return fmt.Errorf("%w: bitmap set rejected", ErrInvalidArgument) - } - return nil -} - -func (e *Engine) bSetLocal(ks *ksRuntime, name string, offset uint64, bit bool) error { - expire := e.expireAt(ks.cfg.TTL) - max := e.maxValueSize - if ks.cfg.MaxValueSize > 0 { - max = ks.cfg.MaxValueSize - } - cur, _ := ks.store.PeekVersion(name) - gate := cur + 1 - applied, tooLarge := ks.store.BSet(name, offset, bit, gate, expire, max) - if tooLarge { - return ErrValueTooLarge - } - if !applied { - return fmt.Errorf("%w: bitmap set rejected", ErrInvalidArgument) - } - ver, _ := ks.store.PeekVersion(name) - ks.observeVersion(name, ver) - e.bReplicateSnapshot(ks, name, ver, expire) - return nil -} - -func (e *Engine) bReplicateSnapshot(ks *ksRuntime, name string, ver uint64, expire int64) { - ent, ok := ks.store.Peek(name) - if !ok || !ent.IsBitmap() { - return - } - e.replicate(ks.cfg.Name, name, store.Entry{ - Value: ent.Value, - Version: ver, - ExpireAt: expire, - Flags: store.FlagBitmap, - }, false) -} - -func (e *Engine) bFetchOwner(ctx context.Context, ks *ksRuntime, name string) (store.Entry, bool, error) { - c := e.clusterSnapshot() - if c == nil || c.Ring == nil || c.Transport == nil { - return store.Entry{}, false, nil - } - owner, ok := c.Ring.Owner(name) - if !ok || owner.ID == "" || owner.ID == c.SelfID || owner.Addr == "" { - return store.Entry{}, false, nil - } - pctx, cancel := e.peerCtx(ctx, ks) - defer cancel() - res, err := c.Transport.GetOrLoad(pctx, owner.Addr, ks.cfg.Name, name) - if err != nil || !res.Found || !res.Entry.IsBitmap() { - return store.Entry{}, false, nil - } - if e.holdsReplica(c, ks, name) { - _ = ks.store.BInstall(name, res.Entry.Value, res.Entry.Version, res.Entry.ExpireAt) - } - return res.Entry, true, nil -} - -func (e *Engine) applyBitmapSet(ks *ksRuntime, name string, inbox []byte, expireAt int64) bool { - offset, bit, err := bitmapx.DecodeSet(inbox) - if err != nil { - return false - } - if expireAt == 0 { - expireAt = e.expireAt(ks.cfg.TTL) - } - max := e.maxValueSize - if ks.cfg.MaxValueSize > 0 { - max = ks.cfg.MaxValueSize - } - cur, _ := ks.store.PeekVersion(name) - gate := cur + 1 - ok, tooLarge := ks.store.BSet(name, offset, bit, gate, expireAt, max) - if !ok || tooLarge { - return false - } - ver, _ := ks.store.PeekVersion(name) - ks.observeVersion(name, ver) - e.bReplicateSnapshot(ks, name, ver, expireAt) - return true -} - -func (e *Engine) applyBitmapInstall(ks *ksRuntime, name string, blob []byte, version uint64, expireAt int64) bool { - if expireAt == 0 { - expireAt = e.expireAt(ks.cfg.TTL) - } - return ks.store.BInstall(name, blob, version, expireAt) -} diff --git a/pkg/engine/bitmap_apply.go b/pkg/engine/bitmap_apply.go new file mode 100644 index 0000000..90dc556 --- /dev/null +++ b/pkg/engine/bitmap_apply.go @@ -0,0 +1,64 @@ +package engine + +import ( + "fmt" + + "github.com/Code0987/supercache/pkg/bitmapx" +) + +// bSetLocal is the owner / single-node write path. +// The store assigns the stored version; we fan PeekVersion after the write. +func (e *Engine) bSetLocal(ks *ksRuntime, name string, offset uint64, bit bool) error { + expire := e.expireAt(ks.cfg.TTL) + max := e.maxValueSize + if ks.cfg.MaxValueSize > 0 { + max = ks.cfg.MaxValueSize + } + cur, _ := ks.store.PeekVersion(name) + gate := cur + 1 + applied, tooLarge := ks.store.BSet(name, offset, bit, gate, expire, max) + if tooLarge { + return ErrValueTooLarge + } + if !applied { + return fmt.Errorf("%w: bitmap set rejected", ErrInvalidArgument) + } + ver, _ := ks.store.PeekVersion(name) + ks.observeVersion(name, ver) + e.bReplicateSnapshot(ks, name, ver, expire) + return nil +} + +// applyBitmapSet is the owner-inbox ApplyPut of FlagBitmapSet. +// Non-owners must not reach here (ApplyPut returns applied=false first). +func (e *Engine) applyBitmapSet(ks *ksRuntime, name string, inbox []byte, expireAt int64) bool { + offset, bit, err := bitmapx.DecodeSet(inbox) + if err != nil { + return false + } + if expireAt == 0 { + expireAt = e.expireAt(ks.cfg.TTL) + } + max := e.maxValueSize + if ks.cfg.MaxValueSize > 0 { + max = ks.cfg.MaxValueSize + } + cur, _ := ks.store.PeekVersion(name) + gate := cur + 1 + ok, tooLarge := ks.store.BSet(name, offset, bit, gate, expireAt, max) + if !ok || tooLarge { + return false + } + ver, _ := ks.store.PeekVersion(name) + ks.observeVersion(name, ver) + e.bReplicateSnapshot(ks, name, ver, expireAt) + return true +} + +// applyBitmapInstall is replica / handoff ApplyPut of FlagBitmap (LWW replace). +func (e *Engine) applyBitmapInstall(ks *ksRuntime, name string, blob []byte, version uint64, expireAt int64) bool { + if expireAt == 0 { + expireAt = e.expireAt(ks.cfg.TTL) + } + return ks.store.BInstall(name, blob, version, expireAt) +} diff --git a/pkg/engine/bitmap_cluster.go b/pkg/engine/bitmap_cluster.go new file mode 100644 index 0000000..e9df40b --- /dev/null +++ b/pkg/engine/bitmap_cluster.go @@ -0,0 +1,65 @@ +package engine + +import ( + "context" + "fmt" + + "github.com/Code0987/supercache/pkg/store" +) + +// bMutViaOwner sends an inbox FlagBitmapSet to the ring owner. +// ACK-only: a rejected apply surfaces as InvalidArgument (no return payload). +func (e *Engine) bMutViaOwner(ctx context.Context, ks *ksRuntime, name string, value []byte) error { + c := e.clusterSnapshot() + owner, _ := c.Ring.Owner(name) + ent := store.Entry{Value: value, Flags: store.FlagBitmapSet, Version: 1} + pctx, cancel := e.peerCtx(ctx, ks) + defer cancel() + applied, err := c.Transport.ApplyPut(pctx, owner.Addr, ks.cfg.Name, name, ent, c.Ring.Generation()) + if err != nil { + return err + } + if !applied { + return fmt.Errorf("%w: bitmap set rejected", ErrInvalidArgument) + } + return nil +} + +// bReplicateSnapshot fans the post-write FlagBitmap blob to RF−1 replicas. +// hintID is (ks, name), so a later snapshot replaces a pending hint — both bits stay. +func (e *Engine) bReplicateSnapshot(ks *ksRuntime, name string, ver uint64, expire int64) { + ent, ok := ks.store.Peek(name) + if !ok || !ent.IsBitmap() { + return + } + e.replicate(ks.cfg.Name, name, store.Entry{ + Value: ent.Value, + Version: ver, + ExpireAt: expire, + Flags: store.FlagBitmap, + }, false) +} + +// bFetchOwner loads a missing local name from the owner (GetOrLoad). +// RPC / !Found / wrong type → miss + nil error (do not return Unavailable). +// Replicas may install the snapshot; non-replicas do not. +func (e *Engine) bFetchOwner(ctx context.Context, ks *ksRuntime, name string) (store.Entry, bool, error) { + c := e.clusterSnapshot() + if c == nil || c.Ring == nil || c.Transport == nil { + return store.Entry{}, false, nil + } + owner, ok := c.Ring.Owner(name) + if !ok || owner.ID == "" || owner.ID == c.SelfID || owner.Addr == "" { + return store.Entry{}, false, nil + } + pctx, cancel := e.peerCtx(ctx, ks) + defer cancel() + res, err := c.Transport.GetOrLoad(pctx, owner.Addr, ks.cfg.Name, name) + if err != nil || !res.Found || !res.Entry.IsBitmap() { + return store.Entry{}, false, nil + } + if e.holdsReplica(c, ks, name) { + _ = ks.store.BInstall(name, res.Entry.Value, res.Entry.Version, res.Entry.ExpireAt) + } + return res.Entry, true, nil +} diff --git a/pkg/store/bitmap.go b/pkg/store/bitmap.go new file mode 100644 index 0000000..0659428 --- /dev/null +++ b/pkg/store/bitmap.go @@ -0,0 +1,174 @@ +package store + +import ( + "container/list" + + "github.com/Code0987/supercache/pkg/bitmapx" +) + +// BSet writes a bit on the named bitmap (creates if missing). +// +// version is only the tombstone-gate floor. The stored version is 1 on create +// or local+1 on a live/tombstone replace — never the inbound number. +func (m *Memory) BSet(key string, offset uint64, bit bool, version uint64, expireAt int64, maxValue int) (applied, tooLarge bool) { + m.mu.Lock() + defer m.mu.Unlock() + + need, ok := bitmapx.EncodedLen(offset) + if !ok { + return false, true + } + if maxValue > 0 && need > maxValue { + return false, true + } + + if el, exists := m.items[key]; exists { + it := el.Value.(*lruItem) + if !it.entry.Expired(m.now()) { + if it.entry.IsTombstone() { + if version <= it.entry.Version { + m.staleSkip.Add(1) + return false, false + } + return m.bCommitLocked(el, it, key, nil, offset, bit, it.entry.Version+1, expireAt, maxValue) + } + if !it.entry.IsBitmap() { + return false, false + } + return m.bCommitLocked(el, it, key, it.entry.Value, offset, bit, it.entry.Version+1, expireAt, maxValue) + } + m.removeElement(el) + } + return m.bInsertLocked(key, offset, bit, 1, expireAt, maxValue) +} + +func (m *Memory) bCommitLocked(el *list.Element, it *lruItem, key string, cur []byte, offset uint64, bit bool, stored uint64, expireAt int64, maxValue int) (applied, tooLarge bool) { + var work []byte + if cur != nil { + work = append([]byte(nil), cur...) + } + next := bitmapx.Set(work, offset, bit) + if maxValue > 0 && len(next) > maxValue { + return false, true + } + oldCost := it.cost + it.entry.Version = stored + it.entry.Flags = FlagBitmap + it.entry.Value = next + if expireAt != 0 { + it.entry.ExpireAt = expireAt + } + it.cost = entryCost(key, it.entry) + m.bytes += it.cost - oldCost + if m.bytes < 0 { + m.bytes = 0 + } + m.order.MoveToFront(el) + m.evictLocked() + _, still := m.items[key] + return still, false +} + +func (m *Memory) bInsertLocked(key string, offset uint64, bit bool, stored uint64, expireAt int64, maxValue int) (applied, tooLarge bool) { + next := bitmapx.Set(nil, offset, bit) + if maxValue > 0 && len(next) > maxValue { + return false, true + } + ent := Entry{Value: next, Version: stored, ExpireAt: expireAt, Flags: FlagBitmap} + return m.insertBitmapLocked(key, ent), false +} + +// BGet returns the bit at offset. Missing → ok=false. +func (m *Memory) BGet(key string, offset uint64) (bool, bool) { + m.mu.Lock() + defer m.mu.Unlock() + if !m.hasBitmapLocked(key) { + return false, false + } + el := m.items[key] + it := el.Value.(*lruItem) + return bitmapx.Get(it.entry.Value, offset), true +} + +// BCount is BITCOUNT over a byte window. Missing → ok=false. +func (m *Memory) BCount(key string, start, end int) (int64, bool) { + m.mu.Lock() + defer m.mu.Unlock() + if !m.hasBitmapLocked(key) { + return 0, false + } + el := m.items[key] + it := el.Value.(*lruItem) + return bitmapx.Count(it.entry.Value, start, end), true +} + +// BPos is BITPOS over a byte window. Missing → ok=false. +func (m *Memory) BPos(key string, bit bool, start, end int) (int64, bool, bool) { + m.mu.Lock() + defer m.mu.Unlock() + if !m.hasBitmapLocked(key) { + return 0, false, false + } + el := m.items[key] + it := el.Value.(*lruItem) + pos, found := bitmapx.Pos(it.entry.Value, bit, start, end) + return pos, found, true +} + +// HasBitmap is the present-bit: live, unexpired, FlagBitmap. +func (m *Memory) HasBitmap(key string) bool { + m.mu.Lock() + defer m.mu.Unlock() + return m.hasBitmapLocked(key) +} + +func (m *Memory) hasBitmapLocked(key string) bool { + el, ok := m.items[key] + if !ok { + return false + } + it := el.Value.(*lruItem) + if it.entry.Expired(m.now()) { + m.removeElement(el) + return false + } + return !it.entry.IsTombstone() && it.entry.IsBitmap() +} + +// BInstall is LWW snapshot handoff: keep blob if version > local. +func (m *Memory) BInstall(key string, blob []byte, version uint64, expireAt int64) bool { + m.mu.Lock() + defer m.mu.Unlock() + if el, ok := m.items[key]; ok { + it := el.Value.(*lruItem) + if !it.entry.Expired(m.now()) { + if it.entry.IsTombstone() { + if version <= it.entry.Version { + m.staleSkip.Add(1) + return false + } + } else if it.entry.IsBitmap() { + if version <= it.entry.Version { + m.staleSkip.Add(1) + return false + } + } else if version <= it.entry.Version { + return false + } + } + m.removeElement(el) + } + ent := Entry{Value: append([]byte(nil), blob...), Version: version, ExpireAt: expireAt, Flags: FlagBitmap} + return m.insertBitmapLocked(key, ent) +} + +func (m *Memory) insertBitmapLocked(key string, ent Entry) bool { + cost := entryCost(key, ent) + it := &lruItem{key: key, entry: copyEntry(ent), cost: cost} + el := m.order.PushFront(it) + m.items[key] = el + m.bytes += cost + m.evictLocked() + _, ok := m.items[key] + return ok +} diff --git a/pkg/store/memory.go b/pkg/store/memory.go index 4647487..4991914 100644 --- a/pkg/store/memory.go +++ b/pkg/store/memory.go @@ -6,7 +6,6 @@ import ( "sync/atomic" "time" - "github.com/Code0987/supercache/pkg/bitmapx" "github.com/Code0987/supercache/pkg/bloom" "github.com/Code0987/supercache/pkg/counter" "github.com/Code0987/supercache/pkg/geo" @@ -2093,153 +2092,6 @@ func (m *Memory) insertJSONLocked(key string, ent Entry, cache any, dirty bool) return ok } -func (m *Memory) BSet(key string, offset uint64, bit bool, version uint64, expireAt int64, maxValue int) (applied, tooLarge bool) { - m.mu.Lock() - defer m.mu.Unlock() - - need, ok := bitmapx.EncodedLen(offset) - if !ok { - return false, true - } - if maxValue > 0 && need > maxValue { - return false, true - } - - if el, exists := m.items[key]; exists { - it := el.Value.(*lruItem) - if !it.entry.Expired(m.now()) { - if it.entry.IsTombstone() { - if version <= it.entry.Version { - m.staleSkip.Add(1) - return false, false - } - return m.bCommitLocked(el, it, key, nil, offset, bit, it.entry.Version+1, expireAt, maxValue) - } - if !it.entry.IsBitmap() { - return false, false - } - return m.bCommitLocked(el, it, key, it.entry.Value, offset, bit, it.entry.Version+1, expireAt, maxValue) - } - m.removeElement(el) - } - return m.bInsertLocked(key, offset, bit, 1, expireAt, maxValue) -} - -func (m *Memory) bCommitLocked(el *list.Element, it *lruItem, key string, cur []byte, offset uint64, bit bool, stored uint64, expireAt int64, maxValue int) (applied, tooLarge bool) { - var work []byte - if cur != nil { - work = append([]byte(nil), cur...) - } - next := bitmapx.Set(work, offset, bit) - if maxValue > 0 && len(next) > maxValue { - return false, true - } - oldCost := it.cost - it.entry.Version = stored - it.entry.Flags = FlagBitmap - it.entry.Value = next - if expireAt != 0 { - it.entry.ExpireAt = expireAt - } - it.cost = entryCost(key, it.entry) - m.bytes += it.cost - oldCost - if m.bytes < 0 { - m.bytes = 0 - } - m.order.MoveToFront(el) - m.evictLocked() - _, still := m.items[key] - return still, false -} - -func (m *Memory) bInsertLocked(key string, offset uint64, bit bool, stored uint64, expireAt int64, maxValue int) (applied, tooLarge bool) { - next := bitmapx.Set(nil, offset, bit) - if maxValue > 0 && len(next) > maxValue { - return false, true - } - ent := Entry{Value: next, Version: stored, ExpireAt: expireAt, Flags: FlagBitmap} - return m.insertBitmapLocked(key, ent), false -} - -func (m *Memory) BGet(key string, offset uint64) (bool, bool) { - m.mu.Lock() - defer m.mu.Unlock() - if !m.hasBitmapLocked(key) { - return false, false - } - el := m.items[key] - it := el.Value.(*lruItem) - return bitmapx.Get(it.entry.Value, offset), true -} - -func (m *Memory) BCount(key string, start, end int) (int64, bool) { - m.mu.Lock() - defer m.mu.Unlock() - if !m.hasBitmapLocked(key) { - return 0, false - } - el := m.items[key] - it := el.Value.(*lruItem) - return bitmapx.Count(it.entry.Value, start, end), true -} - -func (m *Memory) BPos(key string, bit bool, start, end int) (int64, bool, bool) { - m.mu.Lock() - defer m.mu.Unlock() - if !m.hasBitmapLocked(key) { - return 0, false, false - } - el := m.items[key] - it := el.Value.(*lruItem) - pos, found := bitmapx.Pos(it.entry.Value, bit, start, end) - return pos, found, true -} - -func (m *Memory) HasBitmap(key string) bool { - m.mu.Lock() - defer m.mu.Unlock() - return m.hasBitmapLocked(key) -} - -func (m *Memory) hasBitmapLocked(key string) bool { - el, ok := m.items[key] - if !ok { - return false - } - it := el.Value.(*lruItem) - if it.entry.Expired(m.now()) { - m.removeElement(el) - return false - } - return !it.entry.IsTombstone() && it.entry.IsBitmap() -} - -func (m *Memory) BInstall(key string, blob []byte, version uint64, expireAt int64) bool { - m.mu.Lock() - defer m.mu.Unlock() - if el, ok := m.items[key]; ok { - it := el.Value.(*lruItem) - if !it.entry.Expired(m.now()) { - if it.entry.IsTombstone() { - if version <= it.entry.Version { - m.staleSkip.Add(1) - return false - } - } else if it.entry.IsBitmap() { - if version <= it.entry.Version { - m.staleSkip.Add(1) - return false - } - } else if version <= it.entry.Version { - return false - } - } - m.removeElement(el) - } - ent := Entry{Value: append([]byte(nil), blob...), Version: version, ExpireAt: expireAt, Flags: FlagBitmap} - return m.insertBitmapLocked(key, ent) -} - func (m *Memory) HLLAdd(key string, item []byte, version uint64, expireAt int64, maxValue int) (applied, tooLarge bool) { m.mu.Lock() defer m.mu.Unlock() @@ -2372,17 +2224,6 @@ func (m *Memory) insertHLLLocked(key string, ent Entry) bool { return ok } -func (m *Memory) insertBitmapLocked(key string, ent Entry) bool { - cost := entryCost(key, ent) - it := &lruItem{key: key, entry: copyEntry(ent), cost: cost} - el := m.order.PushFront(it) - m.items[key] = el - m.bytes += cost - m.evictLocked() - _, ok := m.items[key] - return ok -} - func (m *Memory) Close() { m.mu.Lock() defer m.mu.Unlock()