github.com/cockroachdb/pebble@v0.0.0-20231214172447-ab4952c5f87b/internal/cache/entry.go (about) 1 // Copyright 2020 The LevelDB-Go and Pebble Authors. All rights reserved. Use 2 // of this source code is governed by a BSD-style license that can be found in 3 // the LICENSE file. 4 5 package cache 6 7 import "sync/atomic" 8 9 type entryType int8 10 11 const ( 12 etTest entryType = iota 13 etCold 14 etHot 15 ) 16 17 func (p entryType) String() string { 18 switch p { 19 case etTest: 20 return "test" 21 case etCold: 22 return "cold" 23 case etHot: 24 return "hot" 25 } 26 return "unknown" 27 } 28 29 // entry holds the metadata for a cache entry. The memory for an entry is 30 // allocated from manually managed memory. 31 // 32 // Using manual memory management for entries is technically a volation of the 33 // Cgo pointer rules: 34 // 35 // https://golang.org/cmd/cgo/#hdr-Passing_pointers 36 // 37 // Specifically, Go pointers should not be stored in C allocated memory. The 38 // reason for this rule is that the Go GC will not look at C allocated memory 39 // to find pointers to Go objects. If the only reference to a Go object is 40 // stored in C allocated memory, the object will be reclaimed. The shard field 41 // of the entry struct points to a Go allocated object, thus the 42 // violation. What makes this "safe" is that the Cache guarantees that there 43 // are other pointers to the shard which will keep it alive. 44 type entry struct { 45 key key 46 // The value associated with the entry. The entry holds a reference on the 47 // value which is maintained by entry.setValue(). 48 val *Value 49 blockLink struct { 50 next *entry 51 prev *entry 52 } 53 fileLink struct { 54 next *entry 55 prev *entry 56 } 57 size int64 58 ptype entryType 59 // referenced is atomically set to indicate that this entry has been accessed 60 // since the last time one of the clock hands swept it. 61 referenced atomic.Bool 62 shard *shard 63 // Reference count for the entry. The entry is freed when the reference count 64 // drops to zero. 65 ref refcnt 66 } 67 68 func newEntry(s *shard, key key, size int64) *entry { 69 e := entryAllocNew() 70 *e = entry{ 71 key: key, 72 size: size, 73 ptype: etCold, 74 shard: s, 75 } 76 e.blockLink.next = e 77 e.blockLink.prev = e 78 e.fileLink.next = e 79 e.fileLink.prev = e 80 e.ref.init(1) 81 return e 82 } 83 84 func (e *entry) free() { 85 e.setValue(nil) 86 *e = entry{} 87 entryAllocFree(e) 88 } 89 90 func (e *entry) next() *entry { 91 if e == nil { 92 return nil 93 } 94 return e.blockLink.next 95 } 96 97 func (e *entry) prev() *entry { 98 if e == nil { 99 return nil 100 } 101 return e.blockLink.prev 102 } 103 104 func (e *entry) link(s *entry) { 105 s.blockLink.prev = e.blockLink.prev 106 s.blockLink.prev.blockLink.next = s 107 s.blockLink.next = e 108 s.blockLink.next.blockLink.prev = s 109 } 110 111 func (e *entry) unlink() *entry { 112 next := e.blockLink.next 113 e.blockLink.prev.blockLink.next = e.blockLink.next 114 e.blockLink.next.blockLink.prev = e.blockLink.prev 115 e.blockLink.prev = e 116 e.blockLink.next = e 117 return next 118 } 119 120 func (e *entry) linkFile(s *entry) { 121 s.fileLink.prev = e.fileLink.prev 122 s.fileLink.prev.fileLink.next = s 123 s.fileLink.next = e 124 s.fileLink.next.fileLink.prev = s 125 } 126 127 func (e *entry) unlinkFile() *entry { 128 next := e.fileLink.next 129 e.fileLink.prev.fileLink.next = e.fileLink.next 130 e.fileLink.next.fileLink.prev = e.fileLink.prev 131 e.fileLink.prev = e 132 e.fileLink.next = e 133 return next 134 } 135 136 func (e *entry) setValue(v *Value) { 137 if v != nil { 138 v.acquire() 139 } 140 old := e.val 141 e.val = v 142 old.release() 143 } 144 145 func (e *entry) peekValue() *Value { 146 return e.val 147 } 148 149 func (e *entry) acquireValue() *Value { 150 v := e.val 151 if v != nil { 152 v.acquire() 153 } 154 return v 155 }