Skip to content

Commit

Permalink
[Chore] Use hashes in the ghost queue
Browse files Browse the repository at this point in the history
  • Loading branch information
maypok86 committed Dec 7, 2023
1 parent 9701531 commit 8592f13
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 40 deletions.
17 changes: 2 additions & 15 deletions internal/node/meta.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
)

Expand All @@ -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
}
Expand Down
53 changes: 30 additions & 23 deletions internal/s3fifo/ghost.go
Original file line number Diff line number Diff line change
@@ -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()
}
5 changes: 3 additions & 2 deletions internal/s3fifo/policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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()
}
Expand All @@ -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)
}
Expand Down
4 changes: 4 additions & 0 deletions internal/s3fifo/small.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 8592f13

Please sign in to comment.