Skip to content

Confirm badgerMove entry required before rewrite#1302

Merged
jarifibrahim merged 4 commits intodgraph-io:masterfrom
tanium:confirm-badgermove-rewrite
May 22, 2020
Merged

Confirm badgerMove entry required before rewrite#1302
jarifibrahim merged 4 commits intodgraph-io:masterfrom
tanium:confirm-badgermove-rewrite

Conversation

@ou05020
Copy link
Copy Markdown
Contributor

@ou05020 ou05020 commented Apr 14, 2020

Value log badgerMove entries for deleted keys are always rewritten.

This leads to exponential DB size growth in heavy write/delete use cases with value pointer entries.

To prevent this, a check has been added to confirm the value is still needed for badgerMove entries.


This change is Reviewable

@ou05020 ou05020 requested a review from a team April 14, 2020 18:00
@CLAassistant
Copy link
Copy Markdown

CLAassistant commented Apr 14, 2020

CLA assistant check
All committers have signed the CLA.

Comment thread value.go Outdated
ou05020 and others added 2 commits April 14, 2020 20:12
Co-Authored-By: Connor Hindley <connor.hindley@tanium.com>
Copy link
Copy Markdown
Contributor

@jarifibrahim jarifibrahim left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:lgtm: Thanks for the PR @ou05020 . I'll get this PR reviewed by @manishrjain

Reviewable status: 0 of 1 files reviewed, 1 unresolved discussion (waiting on @ashish-goswami, @jarifibrahim, @manishrjain, and @ou05020)

Copy link
Copy Markdown
Contributor

@manishrjain manishrjain left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be expensive. Instead, we should check why the current mechanisms of movekey removal don't work.

Reviewable status: 0 of 1 files reviewed, 1 unresolved discussion (waiting on @ashish-goswami, @manishrjain, and @ou05020)

@ou05020
Copy link
Copy Markdown
Contributor Author

ou05020 commented Apr 20, 2020

@manishrjain movekeys are only deleted once it is determined a vlog file satisfies the discard ratio and is rewritten.

However, the discard calculation includes movekey entry size in the total number of bytes (not the discard bytes) in the discard ratio calculation even if that movekey is for a key that has been deleted.

If your discard ratio is 50% and half of a file is used by movekey entries for deleted keys, it will never satisfy the discard ratio allowing it to be rewritten and subsequent movekey deletion.

There are only two approaches I can think of to solve the problem.

Always check if underlying key for each movekey has been deleted to determine if an entry should be discarded.

Or, automatically write a delete movekey entry every time a delete key entry is written. Although that approach will not cleanup existing DB vlog files already in that state and would require a routine similar to the first approach to perform an initial cleanup.

I added db_test.go BenchmarkDbGrowth to demonstrate the size growth problem with badgerMove keys.

If you update value.go discardEntry line 1628 to return false, it will cause the DB size to continue to grow for that test.

@stale stale Bot added the status/stale The issue hasn't had activity for a while and it's marked for closing. label May 20, 2020
@lgalatin lgalatin removed the status/stale The issue hasn't had activity for a while and it's marked for closing. label May 20, 2020
@dgraph-io dgraph-io deleted a comment from stale Bot May 21, 2020
@jarifibrahim
Copy link
Copy Markdown
Contributor

The deleteMoveKeysFor function is supposed to delete the move keys but right now it doesn't work

badger/value.go

Line 685 in 62b7a10

func (vlog *valueLog) deleteMoveKeysFor(fid uint32, tr trace.Trace) error {

because the current implementation of iterators does not return duplicates (keys with same version).
So if the existing state was

level 1 => MoveKeyFoo{version:1, vlog:x}

After rewriting value log file x we will have

Memtable => MoveKeyFoo{version:1, vlog:y}
level 1 => MoveKeyFoo{version:1, vlog:x}

The deleteMoveKeysFor function will never see the key with vlog:x because the iterator skips duplicates keys.

func (mi *MergeIterator) Next() {
for mi.Valid() {
if !bytes.Equal(mi.small.key, mi.curKey) {
break
}
mi.small.next()
mi.fix()

The iterator will see only the vlog;y key because it is at the top.

Even if the iterator were to not skip this key, we will end up losing data if deleteMoveKeysFor function reinserts an old move key with delete marker. Let's assume deleteMoveKeysFor function worked. The new state of the system would be

Memtable/Level 0 => MoveKeyFoo{version:1, vlog:x, DELETE} 
Memtable/Level 0 => MoveKeyFoo{version:1, vlog:y}
level 1 => MoveKeyFoo{version:1, vlog:x}

Compaction would drop all the keys except the one with the delete marker and a Get(foo) would return the wrong value.

Copy link
Copy Markdown
Contributor

@manishrjain manishrjain left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:lgtm: Thanks for the PR!

Reviewable status: 0 of 2 files reviewed, 1 unresolved discussion (waiting on @ashish-goswami and @ou05020)

@jarifibrahim jarifibrahim merged commit 3e1cdd9 into dgraph-io:master May 22, 2020
@jarifibrahim
Copy link
Copy Markdown
Contributor

Thanks for fixing this @ou05020 🎉

NamanJain8 pushed a commit that referenced this pull request Sep 8, 2020
Value log badgerMove entries for deleted keys are always rewritten.
This leads to exponential DB size growth in heavy write/delete use
cases with value pointer entries. To prevent this, a check has been
added to confirm the value is still needed for badgerMove entries.

(cherry picked from commit 3e1cdd9)
NamanJain8 added a commit that referenced this pull request Sep 9, 2020
) (#1502)

* Confirm `badgerMove` entry required before rewrite (#1302)

Value log badgerMove entries for deleted keys are always rewritten.
This leads to exponential DB size growth in heavy write/delete use
cases with value pointer entries. To prevent this, a check has been
added to confirm the value is still needed for badgerMove entries.

(cherry picked from commit 3e1cdd9)

* remove KeepL0InMemory in db_test

Co-authored-by: Julian Hegler <julian.hegler@tanium.com>
jarifibrahim pushed a commit that referenced this pull request Oct 2, 2020
Value log badgerMove entries for deleted keys are always rewritten.
This leads to exponential DB size growth in heavy write/delete use
cases with value pointer entries. To prevent this, a check has been
added to confirm the value is still needed for badgerMove entries.
mYmNeo pushed a commit to mYmNeo/badger that referenced this pull request Jan 16, 2023
…raph-io#1302) (dgraph-io#1502)

* Confirm `badgerMove` entry required before rewrite (dgraph-io#1302)

Value log badgerMove entries for deleted keys are always rewritten.
This leads to exponential DB size growth in heavy write/delete use
cases with value pointer entries. To prevent this, a check has been
added to confirm the value is still needed for badgerMove entries.

(cherry picked from commit 3e1cdd9)

* remove KeepL0InMemory in db_test

Co-authored-by: Julian Hegler <julian.hegler@tanium.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

6 participants