Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

memdb: compatible with Go 1.14's checkptr #14972

Merged
merged 4 commits into from
Feb 28, 2020
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion kv/memdb/arena.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ func newArenaAddr(idx int, offset uint32) arenaAddr {
}

const (
alignMask = 1<<32 - 8 // 29 bit 1 and 3 bit 0.

nullBlockOffset = math.MaxUint32
maxBlockSize = 128 << 20
)
Expand Down Expand Up @@ -117,7 +119,9 @@ func (a *arenaBlock) getFrom(offset uint32) []byte {
}

func (a *arenaBlock) alloc(size int) (uint32, []byte) {
offset := a.length
// We must align the allocated address for node
// to make runtime.checkptrAlignment happy.
offset := (a.length + 7) & alignMask
newLen := offset + size
if newLen > len(a.buf) {
return nullBlockOffset, nil
Expand Down
2 changes: 1 addition & 1 deletion kv/memdb/iterator.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func (it *Iterator) Value() []byte {

// Next moves the iterator to the next entry.
func (it *Iterator) Next() {
it.changeToAddr(it.curr.nexts[0])
it.changeToAddr(it.curr.nexts(0))
}

// Prev moves the iterator to the previous entry.
Expand Down
51 changes: 38 additions & 13 deletions kv/memdb/memdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,21 +39,30 @@ type DB struct {
// This DB is append-only, deleting an entry would remove entry node but not
// reclaim KV buffer.
func New(initBlockSize int) *DB {
return &DB{
db := &DB{
height: 1,
head: nodeWithAddr{node: new(node)},
arena: newArenaLocator(initBlockSize),
}
db.setHeadNode()
return db
}

// Reset resets the DB to initial empty state.
// Release all blocks except the initial one.
func (db *DB) Reset() {
db.height = 1
db.head.node = new(node)
db.length = 0
db.size = 0
db.arena.reset()
db.setHeadNode()
}

func (db *DB) setHeadNode() {
n, _ := db.newNode(db.arena, nil, nil, maxHeight)
for i := 0; i < maxHeight; i++ {
n.setNexts(i, arenaAddr{})
}
db.head.node = n
}

// Get gets the value for the given key. It returns nil if the
Expand Down Expand Up @@ -96,11 +105,11 @@ func (db *DB) Put(key []byte, v []byte) bool {
// We always insert from the base level and up. After you add a node in base level, we cannot
// create a node in the level above because it would have discovered the node in the base level.
for i := 0; i < height; i++ {
x.nexts[i] = next[i].addr
x.setNexts(i, next[i].addr)
if prev[i].node == nil {
prev[i] = db.head
}
prev[i].nexts[i] = addr
prev[i].setNexts(i, addr)
}

x.prev = prev[0].addr
Expand All @@ -125,7 +134,7 @@ func (db *DB) prepareOverwrite(next []nodeWithAddr) int {
height := int(old.height)
for i := 0; i < height; i++ {
if next[i].addr == old.addr {
next[i].addr = old.nexts[i]
next[i].addr = old.nexts(i)
if !next[i].addr.isNull() {
data := db.arena.getFrom(next[i].addr)
next[i].node = (*node)(unsafe.Pointer(&data[0]))
Expand All @@ -152,9 +161,9 @@ func (db *DB) Delete(key []byte) bool {
}

for i := int(keyNode.height) - 1; i >= 0; i-- {
prev[i].nexts[i] = keyNode.nexts[i]
prev[i].setNexts(i, keyNode.nexts(i))
}
nextAddr := keyNode.nexts[0]
nextAddr := keyNode.nexts(0)
if !nextAddr.isNull() {
nextData := db.arena.getFrom(nextAddr)
next := (*node)(unsafe.Pointer(&nextData[0]))
Expand Down Expand Up @@ -184,7 +193,7 @@ func (db *DB) Size() int {
func (db *DB) findSpliceForLevel(arena *arena, key []byte, before nodeWithAddr, level int) (nodeWithAddr, nodeWithAddr, bool) {
for {
// Assume before.key < key.
nextAddr := before.nexts[level]
nextAddr := before.nexts(level)
if nextAddr.isNull() {
return before, nodeWithAddr{}, false
}
Expand All @@ -207,7 +216,7 @@ func (db *DB) findGreaterEqual(key []byte) (*node, []byte, bool) {
for {
var nextData []byte
var next *node
addr := prev.nexts[level]
addr := prev.nexts(level)
if !addr.isNull() {
arena := db.arena
nextData = arena.getFrom(addr)
Expand Down Expand Up @@ -329,8 +338,11 @@ type node struct {

// Addr of previous node at base level.
prev arenaAddr
// Height of the nexts.
nexts [maxHeight]arenaAddr

// node is a variable length struct.
// The nextsBase is the first element of nexts slice,
// it act as the base pointer we do pointer arithmetic in `next` and `setNext`.
nextsBase arenaAddr
}

type nodeWithAddr struct {
Expand All @@ -352,8 +364,21 @@ func (n *node) getValue(buf []byte) []byte {
return buf[nodeLenKeyLen : nodeLenKeyLen+int(n.valLen)]
}

func (n *node) nexts(level int) arenaAddr {
return *n.nextsAddr(level)
}

func (n *node) setNexts(level int, val arenaAddr) {
*n.nextsAddr(level) = val
}

func (n *node) nextsAddr(idx int) *arenaAddr {
offset := uintptr(idx) * unsafe.Sizeof(n.nextsBase)
return (*arenaAddr)(unsafe.Pointer(uintptr(unsafe.Pointer(&n.nextsBase)) + offset))
}

func (db *DB) getNext(n *node, level int) (*node, []byte) {
addr := n.nexts[level]
addr := n.nexts(level)
if addr.isNull() {
return nil, nil
}
Expand Down