github.com/maypok86/otter@v1.2.1/internal/s3fifo/policy.go (about) 1 // Copyright (c) 2023 Alexey Mayshev. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package s3fifo 16 17 import ( 18 "github.com/maypok86/otter/internal/generated/node" 19 ) 20 21 // Policy is an eviction policy based on S3-FIFO eviction algorithm 22 // from the following paper: https://dl.acm.org/doi/10.1145/3600006.3613147. 23 type Policy[K comparable, V any] struct { 24 small *small[K, V] 25 main *main[K, V] 26 ghost *ghost[K, V] 27 maxCost int 28 maxAvailableNodeCost int 29 } 30 31 // NewPolicy creates a new Policy. 32 func NewPolicy[K comparable, V any](maxCost int) *Policy[K, V] { 33 smallMaxCost := maxCost / 10 34 mainMaxCost := maxCost - smallMaxCost 35 36 main := newMain[K, V](mainMaxCost) 37 ghost := newGhost(main) 38 small := newSmall(smallMaxCost, main, ghost) 39 ghost.small = small 40 41 return &Policy[K, V]{ 42 small: small, 43 main: main, 44 ghost: ghost, 45 maxCost: maxCost, 46 maxAvailableNodeCost: smallMaxCost, 47 } 48 } 49 50 // Read updates the eviction policy based on node accesses. 51 func (p *Policy[K, V]) Read(nodes []node.Node[K, V]) { 52 for _, n := range nodes { 53 n.IncrementFrequency() 54 } 55 } 56 57 // Add adds node to the eviction policy. 58 func (p *Policy[K, V]) Add(deleted []node.Node[K, V], n node.Node[K, V]) []node.Node[K, V] { 59 if p.ghost.isGhost(n) { 60 p.main.insert(n) 61 n.ResetFrequency() 62 } else { 63 p.small.insert(n) 64 } 65 66 for p.isFull() { 67 deleted = p.evict(deleted) 68 } 69 70 return deleted 71 } 72 73 func (p *Policy[K, V]) evict(deleted []node.Node[K, V]) []node.Node[K, V] { 74 if p.small.cost >= p.maxCost/10 { 75 return p.small.evict(deleted) 76 } 77 78 return p.main.evict(deleted) 79 } 80 81 func (p *Policy[K, V]) isFull() bool { 82 return p.small.cost+p.main.cost > p.maxCost 83 } 84 85 // Delete deletes node from the eviction policy. 86 func (p *Policy[K, V]) Delete(n node.Node[K, V]) { 87 if n.IsSmall() { 88 p.small.remove(n) 89 return 90 } 91 92 if n.IsMain() { 93 p.main.remove(n) 94 } 95 } 96 97 // MaxAvailableCost returns the maximum available cost of the node. 98 func (p *Policy[K, V]) MaxAvailableCost() int { 99 return p.maxAvailableNodeCost 100 } 101 102 // Clear clears the eviction policy and returns it to the default state. 103 func (p *Policy[K, V]) Clear() { 104 p.ghost.clear() 105 p.main.clear() 106 p.small.clear() 107 }