From 8592f13dd4d8d82e3f7eab3d5d92ab89936e7466 Mon Sep 17 00:00:00 2001 From: maypok86 Date: Thu, 7 Dec 2023 22:47:23 +0300 Subject: [PATCH] [Chore] Use hashes in the ghost queue --- internal/node/meta.go | 17 ++----------- internal/s3fifo/ghost.go | 53 ++++++++++++++++++++++----------------- internal/s3fifo/policy.go | 5 ++-- internal/s3fifo/small.go | 4 +++ 4 files changed, 39 insertions(+), 40 deletions(-) diff --git a/internal/node/meta.go b/internal/node/meta.go index f4a6610..fdec434 100644 --- a/internal/node/meta.go +++ b/internal/node/meta.go @@ -2,9 +2,8 @@ package node const ( deletedMask = uint32(1 << 31) - ghostMask = uint32(1 << 30) - mainMask = uint32(1 << 29) - smallMask = uint32(1 << 28) + mainMask = uint32(1 << 30) + smallMask = uint32(1 << 29) frequencyMask = uint32(4 - 1) ) @@ -22,18 +21,6 @@ func (m Meta) MarkDeleted() Meta { return Meta(uint32(m) | deletedMask) } -func (m Meta) IsGhost() bool { - return uint32(m)&ghostMask == ghostMask -} - -func (m Meta) MarkGhost() Meta { - return Meta(uint32(m) | ghostMask) -} - -func (m Meta) UnmarkGhost() Meta { - return Meta(uint32(m) &^ ghostMask) -} - func (m Meta) IsMain() bool { return uint32(m)&mainMask == mainMask } diff --git a/internal/s3fifo/ghost.go b/internal/s3fifo/ghost.go index 2a1a605..a1effa1 100644 --- a/internal/s3fifo/ghost.go +++ b/internal/s3fifo/ghost.go @@ -1,55 +1,62 @@ package s3fifo import ( + "github.com/dolthub/maphash" + "github.com/dolthub/swiss" "github.com/gammazero/deque" "github.com/maypok86/otter/internal/node" ) type ghost[K comparable, V any] struct { - q *deque.Deque[*node.Node[K, V]] - main *main[K, V] + q *deque.Deque[uint64] + m *swiss.Map[uint64, struct{}] + main *main[K, V] + small *small[K, V] + hasher maphash.Hasher[K] } func newGhost[K comparable, V any](main *main[K, V]) *ghost[K, V] { return &ghost[K, V]{ - q: deque.New[*node.Node[K, V]](main.q.Cap()), - main: main, + q: deque.New[uint64](main.q.Cap()), + m: swiss.NewMap[uint64, struct{}](uint32(main.q.Cap())), + main: main, + hasher: maphash.NewHasher[K](), } } +func (g *ghost[K, V]) isGhost(n *node.Node[K, V]) bool { + _, ok := g.m.Get(g.hasher.Hash(n.Key())) + return ok +} + func (g *ghost[K, V]) insert(deleted []*node.Node[K, V], n *node.Node[K, V]) []*node.Node[K, V] { - if n.Meta.IsGhost() { + n.Meta = n.Meta.MarkDeleted() + deleted = append(deleted, n) + + h := g.hasher.Hash(n.Key()) + + if _, ok := g.m.Get(h); ok { return deleted } - mainLength := g.main.length() - if mainLength == 0 { - n.Meta = n.Meta.MarkDeleted() - return append(deleted, n) + maxLength := g.small.length() + g.main.length() + if maxLength == 0 { + return deleted } - for g.q.Len() >= mainLength { + for g.q.Len() >= maxLength { v := g.q.PopFront() - v.Meta = v.Meta.UnmarkGhost() - if v.Meta.IsDeleted() { - continue - } - - // TODO: add new free buffer - if !v.Meta.IsSmall() && !v.Meta.IsMain() { - // can remove - deleted = append(deleted, v) - v.Meta = v.Meta.MarkDeleted() - } + g.m.Delete(v) } - g.q.PushBack(n) - n.Meta = n.Meta.MarkGhost() + g.q.PushBack(h) + g.m.Put(h, struct{}{}) return deleted } func (g *ghost[K, V]) clear() { g.q.Clear() + g.m.Clear() } diff --git a/internal/s3fifo/policy.go b/internal/s3fifo/policy.go index 69ffd75..f21333e 100644 --- a/internal/s3fifo/policy.go +++ b/internal/s3fifo/policy.go @@ -22,6 +22,7 @@ func NewPolicy[K comparable, V any](maxCost uint32) *Policy[K, V] { main := newMain[K, V](mainMaxCost) ghost := newGhost(main) small := newSmall(smallMaxCost, main, ghost) + ghost.small = small return &Policy[K, V]{ small: small, @@ -48,7 +49,7 @@ func (p *Policy[K, V]) read(deleted []*node.Node[K, V], n *node.Node[K, V]) []*n if n.Meta.IsSmall() || n.Meta.IsMain() { n.Meta = n.Meta.IncrementFrequency() - } else if n.Meta.IsGhost() { + } else if p.ghost.isGhost(n) { deleted = p.insert(deleted, n) n.Meta = n.Meta.ResetFrequency() } @@ -64,7 +65,7 @@ func (p *Policy[K, V]) insert(deleted []*node.Node[K, V], n *node.Node[K, V]) [] return deleted } - if n.Meta.IsGhost() { + if p.ghost.isGhost(n) { if !n.Meta.IsMain() { p.main.insert(n) } diff --git a/internal/s3fifo/small.go b/internal/s3fifo/small.go index 7e8994a..2625aa2 100644 --- a/internal/s3fifo/small.go +++ b/internal/s3fifo/small.go @@ -64,6 +64,10 @@ func (s *small[K, V]) evict(deleted []*node.Node[K, V]) []*node.Node[K, V] { return deleted } +func (s *small[K, V]) length() int { + return s.q.Len() +} + func (s *small[K, V]) clear() { s.q.Clear() s.cost = 0