github.com/alanchchen/go-ethereum@v1.6.6-0.20170601190819-6171d01b1195/swarm/storage/memstore.go (about) 1 // Copyright 2016 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum 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 go-ethereum 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 go-ethereum 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/ethereum/go-ethereum/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 << uint(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 func (s *MemStore) getEntryCnt() uint { 134 return s.entryCnt 135 } 136 137 // entry (not its copy) is going to be in MemStore 138 func (s *MemStore) Put(entry *Chunk) { 139 if s.capacity == 0 { 140 return 141 } 142 143 s.lock.Lock() 144 defer s.lock.Unlock() 145 146 if s.entryCnt >= s.capacity { 147 s.removeOldest() 148 } 149 150 s.accessCnt++ 151 152 node := s.memtree 153 bitpos := uint(0) 154 for node.entry == nil { 155 l := entry.Key.bits(bitpos, node.bits) 156 st := node.subtree[l] 157 if st == nil { 158 st = newMemTree(memTreeLW, node, l) 159 bitpos += node.bits 160 node = st 161 break 162 } 163 bitpos += node.bits 164 node = st 165 } 166 167 if node.entry != nil { 168 169 if node.entry.Key.isEqual(entry.Key) { 170 node.updateAccess(s.accessCnt) 171 if entry.SData == nil { 172 entry.Size = node.entry.Size 173 entry.SData = node.entry.SData 174 } 175 if entry.Req == nil { 176 entry.Req = node.entry.Req 177 } 178 entry.C = node.entry.C 179 node.entry = entry 180 return 181 } 182 183 for node.entry != nil { 184 185 l := node.entry.Key.bits(bitpos, node.bits) 186 st := node.subtree[l] 187 if st == nil { 188 st = newMemTree(memTreeLW, node, l) 189 } 190 st.entry = node.entry 191 node.entry = nil 192 st.updateAccess(node.access[0]) 193 194 l = entry.Key.bits(bitpos, node.bits) 195 st = node.subtree[l] 196 if st == nil { 197 st = newMemTree(memTreeLW, node, l) 198 } 199 bitpos += node.bits 200 node = st 201 202 } 203 } 204 205 node.entry = entry 206 node.lastDBaccess = s.dbAccessCnt 207 node.updateAccess(s.accessCnt) 208 s.entryCnt++ 209 210 return 211 } 212 213 func (s *MemStore) Get(hash Key) (chunk *Chunk, err error) { 214 s.lock.Lock() 215 defer s.lock.Unlock() 216 217 node := s.memtree 218 bitpos := uint(0) 219 for node.entry == nil { 220 l := hash.bits(bitpos, node.bits) 221 st := node.subtree[l] 222 if st == nil { 223 return nil, notFound 224 } 225 bitpos += node.bits 226 node = st 227 } 228 229 if node.entry.Key.isEqual(hash) { 230 s.accessCnt++ 231 node.updateAccess(s.accessCnt) 232 chunk = node.entry 233 if s.dbAccessCnt-node.lastDBaccess > dbForceUpdateAccessCnt { 234 s.dbAccessCnt++ 235 node.lastDBaccess = s.dbAccessCnt 236 if s.dbStore != nil { 237 s.dbStore.updateAccessCnt(hash) 238 } 239 } 240 } else { 241 err = notFound 242 } 243 244 return 245 } 246 247 func (s *MemStore) removeOldest() { 248 node := s.memtree 249 250 for node.entry == nil { 251 252 aidx := uint(0) 253 av := node.access[aidx] 254 255 for aidx < node.width/2-1 { 256 if av == node.access[aidx*2+1] { 257 node.access[aidx] = node.access[aidx*2+2] 258 aidx = aidx*2 + 1 259 } else if av == node.access[aidx*2+2] { 260 node.access[aidx] = node.access[aidx*2+1] 261 aidx = aidx*2 + 2 262 } else { 263 panic(nil) 264 } 265 } 266 pidx := aidx*2 + 2 - node.width 267 if (node.subtree[pidx] != nil) && (av == node.subtree[pidx].access[0]) { 268 if node.subtree[pidx+1] != nil { 269 node.access[aidx] = node.subtree[pidx+1].access[0] 270 } else { 271 node.access[aidx] = 0 272 } 273 } else if (node.subtree[pidx+1] != nil) && (av == node.subtree[pidx+1].access[0]) { 274 if node.subtree[pidx] != nil { 275 node.access[aidx] = node.subtree[pidx].access[0] 276 } else { 277 node.access[aidx] = 0 278 } 279 pidx++ 280 } else { 281 panic(nil) 282 } 283 284 //fmt.Println(pidx) 285 node = node.subtree[pidx] 286 287 } 288 289 if node.entry.dbStored != nil { 290 log.Trace(fmt.Sprintf("Memstore Clean: Waiting for chunk %v to be saved", node.entry.Key.Log())) 291 <-node.entry.dbStored 292 log.Trace(fmt.Sprintf("Memstore Clean: Chunk %v saved to DBStore. Ready to clear from mem.", node.entry.Key.Log())) 293 } else { 294 log.Trace(fmt.Sprintf("Memstore Clean: Chunk %v already in DB. Ready to delete.", node.entry.Key.Log())) 295 } 296 297 if node.entry.SData != nil { 298 node.entry = nil 299 s.entryCnt-- 300 } 301 302 node.access[0] = 0 303 304 //--- 305 306 aidx := uint(0) 307 for { 308 aa := node.access[aidx] 309 if aidx > 0 { 310 aidx = (aidx - 1) >> 1 311 } else { 312 pidx := node.parentIdx 313 node = node.parent 314 if node == nil { 315 return 316 } 317 aidx = (node.width + pidx - 2) >> 1 318 } 319 if (aa != 0) && ((aa < node.access[aidx]) || (node.access[aidx] == 0)) { 320 node.access[aidx] = aa 321 } 322 } 323 } 324 325 // Close memstore 326 func (s *MemStore) Close() { 327 return 328 }