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