unionstore: add checkpoint API to support TiDB savepoint feature (#490)

Signed-off-by: crazycs520 <crazycs520@gmail.com>
This commit is contained in:
crazycs 2022-05-30 13:58:57 +08:00 committed by GitHub
parent 700cbe60d2
commit 75d3f86f3b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 32 additions and 16 deletions

View File

@ -85,14 +85,14 @@ type MemDB struct {
vlogInvalid bool vlogInvalid bool
dirty bool dirty bool
stages []memdbCheckpoint stages []MemDBCheckpoint
} }
func newMemDB() *MemDB { func newMemDB() *MemDB {
db := new(MemDB) db := new(MemDB)
db.allocator.init() db.allocator.init()
db.root = nullAddr db.root = nullAddr
db.stages = make([]memdbCheckpoint, 0, 2) db.stages = make([]MemDBCheckpoint, 0, 2)
db.entrySizeLimit = math.MaxUint64 db.entrySizeLimit = math.MaxUint64
db.bufferSizeLimit = math.MaxUint64 db.bufferSizeLimit = math.MaxUint64
return db return db
@ -155,6 +155,18 @@ func (db *MemDB) Cleanup(h int) {
db.stages = db.stages[:h-1] db.stages = db.stages[:h-1]
} }
// Checkpoint returns a checkpoint of MemDB.
func (db *MemDB) Checkpoint() *MemDBCheckpoint {
cp := db.vlog.checkpoint()
return &cp
}
// RevertToCheckpoint reverts the MemDB to the checkpoint.
func (db *MemDB) RevertToCheckpoint(cp *MemDBCheckpoint) {
db.vlog.revertToCheckpoint(db, cp)
db.vlog.truncate(cp)
}
// Reset resets the MemBuffer to initial states. // Reset resets the MemBuffer to initial states.
func (db *MemDB) Reset() { func (db *MemDB) Reset() {
db.root = nullAddr db.root = nullAddr
@ -338,7 +350,7 @@ func (db *MemDB) set(key []byte, value []byte, ops ...kv.FlagsOp) error {
} }
func (db *MemDB) setValue(x memdbNodeAddr, value []byte) { func (db *MemDB) setValue(x memdbNodeAddr, value []byte) {
var activeCp *memdbCheckpoint var activeCp *MemDBCheckpoint
if len(db.stages) > 0 { if len(db.stages) > 0 {
activeCp = &db.stages[len(db.stages)-1] activeCp = &db.stages[len(db.stages)-1]
} }

View File

@ -167,18 +167,19 @@ func (a *memdbArenaBlock) reset() {
a.length = 0 a.length = 0
} }
type memdbCheckpoint struct { // MemDBCheckpoint is the checkpoint of memory DB.
type MemDBCheckpoint struct {
blockSize int blockSize int
blocks int blocks int
offsetInBlock int offsetInBlock int
} }
func (cp *memdbCheckpoint) isSamePosition(other *memdbCheckpoint) bool { func (cp *MemDBCheckpoint) isSamePosition(other *MemDBCheckpoint) bool {
return cp.blocks == other.blocks && cp.offsetInBlock == other.offsetInBlock return cp.blocks == other.blocks && cp.offsetInBlock == other.offsetInBlock
} }
func (a *memdbArena) checkpoint() memdbCheckpoint { func (a *memdbArena) checkpoint() MemDBCheckpoint {
snap := memdbCheckpoint{ snap := MemDBCheckpoint{
blockSize: a.blockSize, blockSize: a.blockSize,
blocks: len(a.blocks), blocks: len(a.blocks),
} }
@ -188,7 +189,7 @@ func (a *memdbArena) checkpoint() memdbCheckpoint {
return snap return snap
} }
func (a *memdbArena) truncate(snap *memdbCheckpoint) { func (a *memdbArena) truncate(snap *MemDBCheckpoint) {
for i := snap.blocks; i < len(a.blocks); i++ { for i := snap.blocks; i < len(a.blocks); i++ {
a.blocks[i] = memdbArenaBlock{} a.blocks[i] = memdbArenaBlock{}
} }
@ -310,7 +311,7 @@ func (l *memdbVlog) getValue(addr memdbArenaAddr) []byte {
return block[valueOff:lenOff:lenOff] return block[valueOff:lenOff:lenOff]
} }
func (l *memdbVlog) getSnapshotValue(addr memdbArenaAddr, snap *memdbCheckpoint) ([]byte, bool) { func (l *memdbVlog) getSnapshotValue(addr memdbArenaAddr, snap *MemDBCheckpoint) ([]byte, bool) {
result := l.selectValueHistory(addr, func(addr memdbArenaAddr) bool { result := l.selectValueHistory(addr, func(addr memdbArenaAddr) bool {
return !l.canModify(snap, addr) return !l.canModify(snap, addr)
}) })
@ -332,7 +333,7 @@ func (l *memdbVlog) selectValueHistory(addr memdbArenaAddr, predicate func(memdb
return nullAddr return nullAddr
} }
func (l *memdbVlog) revertToCheckpoint(db *MemDB, cp *memdbCheckpoint) { func (l *memdbVlog) revertToCheckpoint(db *MemDB, cp *MemDBCheckpoint) {
cursor := l.checkpoint() cursor := l.checkpoint()
for !cp.isSamePosition(&cursor) { for !cp.isSamePosition(&cursor) {
hdrOff := cursor.offsetInBlock - memdbVlogHdrSize hdrOff := cursor.offsetInBlock - memdbVlogHdrSize
@ -361,7 +362,7 @@ func (l *memdbVlog) revertToCheckpoint(db *MemDB, cp *memdbCheckpoint) {
} }
} }
func (l *memdbVlog) inspectKVInLog(db *MemDB, head, tail *memdbCheckpoint, f func([]byte, kv.KeyFlags, []byte)) { func (l *memdbVlog) inspectKVInLog(db *MemDB, head, tail *MemDBCheckpoint, f func([]byte, kv.KeyFlags, []byte)) {
cursor := *tail cursor := *tail
for !head.isSamePosition(&cursor) { for !head.isSamePosition(&cursor) {
cursorAddr := memdbArenaAddr{idx: uint32(cursor.blocks - 1), off: uint32(cursor.offsetInBlock)} cursorAddr := memdbArenaAddr{idx: uint32(cursor.blocks - 1), off: uint32(cursor.offsetInBlock)}
@ -381,7 +382,7 @@ func (l *memdbVlog) inspectKVInLog(db *MemDB, head, tail *memdbCheckpoint, f fun
} }
} }
func (l *memdbVlog) moveBackCursor(cursor *memdbCheckpoint, hdr *memdbVlogHdr) { func (l *memdbVlog) moveBackCursor(cursor *MemDBCheckpoint, hdr *memdbVlogHdr) {
cursor.offsetInBlock -= (memdbVlogHdrSize + int(hdr.valueLen)) cursor.offsetInBlock -= (memdbVlogHdrSize + int(hdr.valueLen))
if cursor.offsetInBlock == 0 { if cursor.offsetInBlock == 0 {
cursor.blocks-- cursor.blocks--
@ -391,7 +392,7 @@ func (l *memdbVlog) moveBackCursor(cursor *memdbCheckpoint, hdr *memdbVlogHdr) {
} }
} }
func (l *memdbVlog) canModify(cp *memdbCheckpoint, addr memdbArenaAddr) bool { func (l *memdbVlog) canModify(cp *MemDBCheckpoint, addr memdbArenaAddr) bool {
if cp == nil { if cp == nil {
return true return true
} }

View File

@ -60,7 +60,7 @@ func (db *MemDB) SnapshotIter(start, end []byte) Iterator {
return it return it
} }
func (db *MemDB) getSnapshot() memdbCheckpoint { func (db *MemDB) getSnapshot() MemDBCheckpoint {
if len(db.stages) > 0 { if len(db.stages) > 0 {
return db.stages[0] return db.stages[0]
} }
@ -69,7 +69,7 @@ func (db *MemDB) getSnapshot() memdbCheckpoint {
type memdbSnapGetter struct { type memdbSnapGetter struct {
db *MemDB db *MemDB
cp memdbCheckpoint cp MemDBCheckpoint
} }
func (snap *memdbSnapGetter) Get(key []byte) ([]byte, error) { func (snap *memdbSnapGetter) Get(key []byte) ([]byte, error) {
@ -91,7 +91,7 @@ func (snap *memdbSnapGetter) Get(key []byte) ([]byte, error) {
type memdbSnapIter struct { type memdbSnapIter struct {
*MemdbIterator *MemdbIterator
value []byte value []byte
cp memdbCheckpoint cp MemDBCheckpoint
} }
func (i *memdbSnapIter) Value() []byte { func (i *memdbSnapIter) Value() []byte {

View File

@ -51,3 +51,6 @@ type Iterator = unionstore.Iterator
// When discarding a newly added KV in `Cleanup`, the non-persistent flags will be cleared. // When discarding a newly added KV in `Cleanup`, the non-persistent flags will be cleared.
// If there are persistent flags associated with key, we will keep this key in node without value. // If there are persistent flags associated with key, we will keep this key in node without value.
type MemDB = unionstore.MemDB type MemDB = unionstore.MemDB
// MemDBCheckpoint is the checkpoint of memory DB.
type MemDBCheckpoint = unionstore.MemDBCheckpoint