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

Confirm badgerMove entry required before rewrite #1302

Merged
merged 4 commits into from
May 22, 2020

Conversation

ou05020
Copy link
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

@CLAassistant
Copy link

CLAassistant commented Apr 14, 2020

CLA assistant check
All committers have signed the CLA.

value.go Outdated Show resolved Hide resolved
Copy link
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
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
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
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
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
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 <[email protected]>
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 <[email protected]>
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