github.com/SmartMeshFoundation/Spectrum@v0.0.0-20220621030607-452a266fee1e/swarm/storage/memstore.go (about) 1 // Copyright 2016 The Spectrum Authors 2 // This file is part of the Spectrum library. 3 // 4 // The Spectrum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The Spectrum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the Spectrum library. If not, see <http://www.gnu.org/licenses/>. 16 17 // memory storage layer for the package blockhash 18 19 package storage 20 21 import ( 22 "fmt" 23 "sync" 24 25 "github.com/SmartMeshFoundation/Spectrum/log" 26 ) 27 28 const ( 29 memTreeLW = 2 // log2(subtree count) of the subtrees 30 memTreeFLW = 14 // log2(subtree count) of the root layer 31 dbForceUpdateAccessCnt = 1000 32 defaultCacheCapacity = 5000 33 ) 34 35 type MemStore struct { 36 memtree *memTree 37 entryCnt, capacity uint // stored entries 38 accessCnt uint64 // access counter; oldest is thrown away when full 39 dbAccessCnt uint64 40 dbStore *DbStore 41 lock sync.Mutex 42 } 43 44 /* 45 a hash prefix subtree containing subtrees or one storage entry (but never both) 46 47 - access[0] stores the smallest (oldest) access count value in this subtree 48 - if it contains more subtrees and its subtree count is at least 4, access[1:2] 49 stores the smallest access count in the first and second halves of subtrees 50 (so that access[0] = min(access[1], access[2]) 51 - likewise, if subtree count is at least 8, 52 access[1] = min(access[3], access[4]) 53 access[2] = min(access[5], access[6]) 54 (access[] is a binary tree inside the multi-bit leveled hash tree) 55 */ 56 57 func NewMemStore(d *DbStore, capacity uint) (m *MemStore) { 58 m = &MemStore{} 59 m.memtree = newMemTree(memTreeFLW, nil, 0) 60 m.dbStore = d 61 m.setCapacity(capacity) 62 return 63 } 64 65 type memTree struct { 66 subtree []*memTree 67 parent *memTree 68 parentIdx uint 69 70 bits uint // log2(subtree count) 71 width uint // subtree count 72 73 entry *Chunk // if subtrees are present, entry should be nil 74 lastDBaccess uint64 75 access []uint64 76 } 77 78 func newMemTree(b uint, parent *memTree, pidx uint) (node *memTree) { 79 node = new(memTree) 80 node.bits = b 81 node.width = 1 << b 82 node.subtree = make([]*memTree, node.width) 83 node.access = make([]uint64, node.width-1) 84 node.parent = parent 85 node.parentIdx = pidx 86 if parent != nil { 87 parent.subtree[pidx] = node 88 } 89 90 return node 91 } 92 93 func (node *memTree) updateAccess(a uint64) { 94 aidx := uint(0) 95 var aa uint64 96 oa := node.access[0] 97 for node.access[aidx] == oa { 98 node.access[aidx] = a 99 if aidx > 0 { 100 aa = node.access[((aidx-1)^1)+1] 101 aidx = (aidx - 1) >> 1 102 } else { 103 pidx := node.parentIdx 104 node = node.parent 105 if node == nil { 106 return 107 } 108 nn := node.subtree[pidx^1] 109 if nn != nil { 110 aa = nn.access[0] 111 } else { 112 aa = 0 113 } 114 aidx = (node.width + pidx - 2) >> 1 115 } 116 117 if (aa != 0) && (aa < a) { 118 a = aa 119 } 120 } 121 } 122 123 func (s *MemStore) setCapacity(c uint) { 124 s.lock.Lock() 125 defer s.lock.Unlock() 126 127 for c < s.entryCnt { 128 s.removeOldest() 129 } 130 s.capacity = c 131 } 132 133 // entry (not its copy) is going to be in MemStore 134 func (s *MemStore) Put(entry *Chunk) { 135 if s.capacity == 0 { 136 return 137 } 138 139 s.lock.Lock() 140 defer s.lock.Unlock() 141 142 if s.entryCnt >= s.capacity { 143 s.removeOldest() 144 } 145 146 s.accessCnt++ 147 148 node := s.memtree 149 bitpos := uint(0) 150 for node.entry == nil { 151 l := entry.Key.bits(bitpos, node.bits) 152 st := node.subtree[l] 153 if st == nil { 154 st = newMemTree(memTreeLW, node, l) 155 bitpos += node.bits 156 node = st 157 break 158 } 159 bitpos += node.bits 160 node = st 161 } 162 163 if node.entry != nil { 164 165 if node.entry.Key.isEqual(entry.Key) { 166 node.updateAccess(s.accessCnt) 167 if entry.SData == nil { 168 entry.Size = node.entry.Size 169 entry.SData = node.entry.SData 170 } 171 if entry.Req == nil { 172 entry.Req = node.entry.Req 173 } 174 entry.C = node.entry.C 175 node.entry = entry 176 return 177 } 178 179 for node.entry != nil { 180 181 l := node.entry.Key.bits(bitpos, node.bits) 182 st := node.subtree[l] 183 if st == nil { 184 st = newMemTree(memTreeLW, node, l) 185 } 186 st.entry = node.entry 187 node.entry = nil 188 st.updateAccess(node.access[0]) 189 190 l = entry.Key.bits(bitpos, node.bits) 191 st = node.subtree[l] 192 if st == nil { 193 st = newMemTree(memTreeLW, node, l) 194 } 195 bitpos += node.bits 196 node = st 197 198 } 199 } 200 201 node.entry = entry 202 node.lastDBaccess = s.dbAccessCnt 203 node.updateAccess(s.accessCnt) 204 s.entryCnt++ 205 } 206 207 func (s *MemStore) Get(hash Key) (chunk *Chunk, err error) { 208 s.lock.Lock() 209 defer s.lock.Unlock() 210 211 node := s.memtree 212 bitpos := uint(0) 213 for node.entry == nil { 214 l := hash.bits(bitpos, node.bits) 215 st := node.subtree[l] 216 if st == nil { 217 return nil, notFound 218 } 219 bitpos += node.bits 220 node = st 221 } 222 223 if node.entry.Key.isEqual(hash) { 224 s.accessCnt++ 225 node.updateAccess(s.accessCnt) 226 chunk = node.entry 227 if s.dbAccessCnt-node.lastDBaccess > dbForceUpdateAccessCnt { 228 s.dbAccessCnt++ 229 node.lastDBaccess = s.dbAccessCnt 230 if s.dbStore != nil { 231 s.dbStore.updateAccessCnt(hash) 232 } 233 } 234 } else { 235 err = notFound 236 } 237 238 return 239 } 240 241 func (s *MemStore) removeOldest() { 242 node := s.memtree 243 244 for node.entry == nil { 245 246 aidx := uint(0) 247 av := node.access[aidx] 248 249 for aidx < node.width/2-1 { 250 if av == node.access[aidx*2+1] { 251 node.access[aidx] = node.access[aidx*2+2] 252 aidx = aidx*2 + 1 253 } else if av == node.access[aidx*2+2] { 254 node.access[aidx] = node.access[aidx*2+1] 255 aidx = aidx*2 + 2 256 } else { 257 panic(nil) 258 } 259 } 260 pidx := aidx*2 + 2 - node.width 261 if (node.subtree[pidx] != nil) && (av == node.subtree[pidx].access[0]) { 262 if node.subtree[pidx+1] != nil { 263 node.access[aidx] = node.subtree[pidx+1].access[0] 264 } else { 265 node.access[aidx] = 0 266 } 267 } else if (node.subtree[pidx+1] != nil) && (av == node.subtree[pidx+1].access[0]) { 268 if node.subtree[pidx] != nil { 269 node.access[aidx] = node.subtree[pidx].access[0] 270 } else { 271 node.access[aidx] = 0 272 } 273 pidx++ 274 } else { 275 panic(nil) 276 } 277 278 //fmt.Println(pidx) 279 node = node.subtree[pidx] 280 281 } 282 283 if node.entry.dbStored != nil { 284 log.Trace(fmt.Sprintf("Memstore Clean: Waiting for chunk %v to be saved", node.entry.Key.Log())) 285 <-node.entry.dbStored 286 log.Trace(fmt.Sprintf("Memstore Clean: Chunk %v saved to DBStore. Ready to clear from mem.", node.entry.Key.Log())) 287 } else { 288 log.Trace(fmt.Sprintf("Memstore Clean: Chunk %v already in DB. Ready to delete.", node.entry.Key.Log())) 289 } 290 291 if node.entry.SData != nil { 292 node.entry = nil 293 s.entryCnt-- 294 } 295 296 node.access[0] = 0 297 298 //--- 299 300 aidx := uint(0) 301 for { 302 aa := node.access[aidx] 303 if aidx > 0 { 304 aidx = (aidx - 1) >> 1 305 } else { 306 pidx := node.parentIdx 307 node = node.parent 308 if node == nil { 309 return 310 } 311 aidx = (node.width + pidx - 2) >> 1 312 } 313 if (aa != 0) && ((aa < node.access[aidx]) || (node.access[aidx] == 0)) { 314 node.access[aidx] = aa 315 } 316 } 317 } 318 319 // Close memstore 320 func (s *MemStore) Close() {}