github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/allegrosql/memdb_arena.go (about) 1 // Copyright 2020 WHTCORPS INC, Inc. 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 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package ekv 15 16 import ( 17 "encoding/binary" 18 "math" 19 "unsafe" 20 ) 21 22 const ( 23 alignMask = 1<<32 - 8 // 29 bit 1 and 3 bit 0. 24 25 nullBlockOffset = math.MaxUint32 26 maxBlockSize = 128 << 20 27 initBlockSize = 4 * 1024 28 ) 29 30 var ( 31 nullAddr = memdbMemCamAddr{math.MaxUint32, math.MaxUint32} 32 endian = binary.LittleEndian 33 ) 34 35 type memdbMemCamAddr struct { 36 idx uint32 37 off uint32 38 } 39 40 func (addr memdbMemCamAddr) isNull() bool { 41 return addr == nullAddr 42 } 43 44 // causetstore and load is used by vlog, due to pointer in vlog is not aligned. 45 46 func (addr memdbMemCamAddr) causetstore(dst []byte) { 47 endian.PutUint32(dst, addr.idx) 48 endian.PutUint32(dst[4:], addr.off) 49 } 50 51 func (addr *memdbMemCamAddr) load(src []byte) { 52 addr.idx = endian.Uint32(src) 53 addr.off = endian.Uint32(src[4:]) 54 } 55 56 type memdbMemCam struct { 57 blockSize int 58 blocks []memdbMemCamBlock 59 } 60 61 func (a *memdbMemCam) alloc(size int, align bool) (memdbMemCamAddr, []byte) { 62 if size > maxBlockSize { 63 panic("alloc size is larger than max causet size") 64 } 65 66 if len(a.blocks) == 0 { 67 a.enlarge(size, initBlockSize) 68 } 69 70 addr, data := a.allocInLastBlock(size, align) 71 if !addr.isNull() { 72 return addr, data 73 } 74 75 a.enlarge(size, a.blockSize<<1) 76 return a.allocInLastBlock(size, align) 77 } 78 79 func (a *memdbMemCam) enlarge(allocSize, blockSize int) { 80 a.blockSize = blockSize 81 for a.blockSize <= allocSize { 82 a.blockSize <<= 1 83 } 84 // Size will never larger than maxBlockSize. 85 if a.blockSize > maxBlockSize { 86 a.blockSize = maxBlockSize 87 } 88 a.blocks = append(a.blocks, memdbMemCamBlock{ 89 buf: make([]byte, a.blockSize), 90 }) 91 } 92 93 func (a *memdbMemCam) allocInLastBlock(size int, align bool) (memdbMemCamAddr, []byte) { 94 idx := len(a.blocks) - 1 95 offset, data := a.blocks[idx].alloc(size, align) 96 if offset == nullBlockOffset { 97 return nullAddr, nil 98 } 99 return memdbMemCamAddr{uint32(idx), offset}, data 100 } 101 102 func (a *memdbMemCam) reset() { 103 for i := range a.blocks { 104 a.blocks[i].reset() 105 } 106 a.blocks = a.blocks[:0] 107 a.blockSize = 0 108 } 109 110 type memdbMemCamBlock struct { 111 buf []byte 112 length int 113 } 114 115 func (a *memdbMemCamBlock) alloc(size int, align bool) (uint32, []byte) { 116 offset := a.length 117 if align { 118 // We must align the allocated address for node 119 // to make runtime.checkptrAlignment happy. 120 offset = (a.length + 7) & alignMask 121 } 122 newLen := offset + size 123 if newLen > len(a.buf) { 124 return nullBlockOffset, nil 125 } 126 a.length = newLen 127 return uint32(offset), a.buf[offset : offset+size] 128 } 129 130 func (a *memdbMemCamBlock) reset() { 131 a.buf = nil 132 a.length = 0 133 } 134 135 type memdbCheckpoint struct { 136 blockSize int 137 blocks int 138 offsetInBlock int 139 } 140 141 func (cp *memdbCheckpoint) isSamePosition(other *memdbCheckpoint) bool { 142 return cp.blocks == other.blocks && cp.offsetInBlock == other.offsetInBlock 143 } 144 145 func (a *memdbMemCam) checkpoint() memdbCheckpoint { 146 snap := memdbCheckpoint{ 147 blockSize: a.blockSize, 148 blocks: len(a.blocks), 149 } 150 if len(a.blocks) > 0 { 151 snap.offsetInBlock = a.blocks[len(a.blocks)-1].length 152 } 153 return snap 154 } 155 156 func (a *memdbMemCam) truncate(snap *memdbCheckpoint) { 157 for i := snap.blocks; i < len(a.blocks); i++ { 158 a.blocks[i] = memdbMemCamBlock{} 159 } 160 a.blocks = a.blocks[:snap.blocks] 161 if len(a.blocks) > 0 { 162 a.blocks[len(a.blocks)-1].length = snap.offsetInBlock 163 } 164 a.blockSize = snap.blockSize 165 } 166 167 type nodeSlabPredictor struct { 168 memdbMemCam 169 170 // Dummy node, so that we can make X.left.up = X. 171 // We then use this instead of NULL to mean the top or bottom 172 // end of the rb tree. It is a black node. 173 nullNode memdbNode 174 } 175 176 func (a *nodeSlabPredictor) init() { 177 a.nullNode = memdbNode{ 178 up: nullAddr, 179 left: nullAddr, 180 right: nullAddr, 181 vptr: nullAddr, 182 } 183 } 184 185 func (a *nodeSlabPredictor) getNode(addr memdbMemCamAddr) *memdbNode { 186 if addr.isNull() { 187 return &a.nullNode 188 } 189 190 return (*memdbNode)(unsafe.Pointer(&a.blocks[addr.idx].buf[addr.off])) 191 } 192 193 func (a *nodeSlabPredictor) allocNode(key Key) (memdbMemCamAddr, *memdbNode) { 194 nodeSize := 8*4 + 2 + 1 + len(key) 195 addr, mem := a.alloc(nodeSize, true) 196 n := (*memdbNode)(unsafe.Pointer(&mem[0])) 197 n.vptr = nullAddr 198 n.klen = uint16(len(key)) 199 copy(n.getKey(), key) 200 return addr, n 201 } 202 203 var testMode = false 204 205 func (a *nodeSlabPredictor) freeNode(addr memdbMemCamAddr) { 206 if testMode { 207 // Make it easier for debug. 208 n := a.getNode(addr) 209 badAddr := nullAddr 210 badAddr.idx-- 211 n.left = badAddr 212 n.right = badAddr 213 n.up = badAddr 214 n.vptr = badAddr 215 return 216 } 217 // TODO: reuse freed nodes. 218 } 219 220 func (a *nodeSlabPredictor) reset() { 221 a.memdbMemCam.reset() 222 a.init() 223 } 224 225 type memdbVlog struct { 226 memdbMemCam 227 } 228 229 const memdbVlogHdrSize = 8 + 8 + 4 230 231 type memdbVlogHdr struct { 232 nodeAddr memdbMemCamAddr 233 oldValue memdbMemCamAddr 234 valueLen uint32 235 } 236 237 func (hdr *memdbVlogHdr) causetstore(dst []byte) { 238 cursor := 0 239 endian.PutUint32(dst[cursor:], hdr.valueLen) 240 cursor += 4 241 hdr.oldValue.causetstore(dst[cursor:]) 242 cursor += 8 243 hdr.nodeAddr.causetstore(dst[cursor:]) 244 } 245 246 func (hdr *memdbVlogHdr) load(src []byte) { 247 cursor := 0 248 hdr.valueLen = endian.Uint32(src[cursor:]) 249 cursor += 4 250 hdr.oldValue.load(src[cursor:]) 251 cursor += 8 252 hdr.nodeAddr.load(src[cursor:]) 253 } 254 255 func (l *memdbVlog) appendValue(nodeAddr memdbMemCamAddr, oldValue memdbMemCamAddr, value []byte) memdbMemCamAddr { 256 size := memdbVlogHdrSize + len(value) 257 addr, mem := l.alloc(size, false) 258 259 copy(mem, value) 260 hdr := memdbVlogHdr{nodeAddr, oldValue, uint32(len(value))} 261 hdr.causetstore(mem[len(value):]) 262 263 addr.off += uint32(size) 264 return addr 265 } 266 267 func (l *memdbVlog) getValue(addr memdbMemCamAddr) []byte { 268 lenOff := addr.off - memdbVlogHdrSize 269 causet := l.blocks[addr.idx].buf 270 valueLen := endian.Uint32(causet[lenOff:]) 271 if valueLen == 0 { 272 return tombstone 273 } 274 valueOff := lenOff - valueLen 275 return causet[valueOff:lenOff:lenOff] 276 } 277 278 func (l *memdbVlog) getSnapshotValue(addr memdbMemCamAddr, snap *memdbCheckpoint) ([]byte, bool) { 279 for !addr.isNull() { 280 if !l.canModify(snap, addr) { 281 return l.getValue(addr), true 282 } 283 var hdr memdbVlogHdr 284 hdr.load(l.blocks[addr.idx].buf[addr.off-memdbVlogHdrSize:]) 285 addr = hdr.oldValue 286 } 287 return nil, false 288 } 289 290 func (l *memdbVlog) revertToCheckpoint(EDB *memdb, cp *memdbCheckpoint) { 291 cursor := l.checkpoint() 292 for !cp.isSamePosition(&cursor) { 293 hdrOff := cursor.offsetInBlock - memdbVlogHdrSize 294 causet := l.blocks[cursor.blocks-1].buf 295 var hdr memdbVlogHdr 296 hdr.load(causet[hdrOff:]) 297 node := EDB.getNode(hdr.nodeAddr) 298 299 node.vptr = hdr.oldValue 300 EDB.size -= int(hdr.valueLen) 301 // oldValue.isNull() == true means this is a newly added value. 302 if hdr.oldValue.isNull() { 303 // If there are no flags associated with this key, we need to delete this node. 304 keptFlags := node.getKeyFlags() & persistentFlags 305 if keptFlags == 0 { 306 EDB.deleteNode(node) 307 } else { 308 node.setKeyFlags(keptFlags) 309 EDB.dirty = true 310 } 311 } else { 312 EDB.size += len(l.getValue(hdr.oldValue)) 313 } 314 315 l.moveBackCursor(&cursor, &hdr) 316 } 317 } 318 319 func (l *memdbVlog) inspectKVInLog(EDB *memdb, head, tail *memdbCheckpoint, f func(Key, KeyFlags, []byte)) { 320 cursor := *tail 321 for !head.isSamePosition(&cursor) { 322 cursorAddr := memdbMemCamAddr{idx: uint32(cursor.blocks - 1), off: uint32(cursor.offsetInBlock)} 323 hdrOff := cursorAddr.off - memdbVlogHdrSize 324 causet := l.blocks[cursorAddr.idx].buf 325 var hdr memdbVlogHdr 326 hdr.load(causet[hdrOff:]) 327 node := EDB.allocator.getNode(hdr.nodeAddr) 328 329 // Skip older versions. 330 if node.vptr == cursorAddr { 331 value := causet[hdrOff-hdr.valueLen : hdrOff] 332 f(node.getKey(), node.getKeyFlags(), value) 333 } 334 335 l.moveBackCursor(&cursor, &hdr) 336 } 337 } 338 339 func (l *memdbVlog) moveBackCursor(cursor *memdbCheckpoint, hdr *memdbVlogHdr) { 340 cursor.offsetInBlock -= (memdbVlogHdrSize + int(hdr.valueLen)) 341 if cursor.offsetInBlock == 0 { 342 cursor.blocks-- 343 if cursor.blocks > 0 { 344 cursor.offsetInBlock = l.blocks[cursor.blocks-1].length 345 } 346 } 347 } 348 349 func (l *memdbVlog) canModify(cp *memdbCheckpoint, addr memdbMemCamAddr) bool { 350 if cp == nil { 351 return true 352 } 353 if int(addr.idx) > cp.blocks-1 { 354 return true 355 } 356 if int(addr.idx) == cp.blocks-1 && int(addr.off) > cp.offsetInBlock { 357 return true 358 } 359 return false 360 }