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  }