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

save a key comparison in block seeks #6646

Closed
wants to merge 3 commits into from

Conversation

ajkr
Copy link
Contributor

@ajkr ajkr commented Apr 3, 2020

This saves up to two key comparisons in block seeks. The first key
comparison saved is a redundant key comparison against the restart key
where the linear scan starts. This comparison is saved in all cases
except when the found key is in the first restart interval. The
second key comparison saved is a redundant key comparison against the
restart key where the linear scan ends. This is only saved in cases
where all keys in the restart interval are less than the target
(probability roughly 1/restart_interval).

Test Plan:

ran readrandom with mostly default settings and counted key comparisons
using PerfContext.

before: user_key_comparison_count = 30370310
after: user_key_comparison_count = 28881965

setup command:

$ TEST_TMPDIR=/dev/shm/dbbench ./db_bench -benchmarks=fillrandom,compact -write_buffer_size=1048576 -target_file_size_base=1048576 -max_bytes_for_level_base=4194304 -max_background_jobs=12 -level_compaction_dynamic_level_bytes=true -num=10000000

benchmark command:

$ TEST_TMPDIR=/dev/shm/dbbench/ ./db_bench -use_existing_db=true -benchmarks=readrandom -disable_auto_compactions=true -num=10000000 -compression_type=none -reads=1000000 -perf_level=3

Copy link
Contributor

@facebook-github-bot facebook-github-bot left a comment

Choose a reason for hiding this comment

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

@ajkr has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.

@ajkr
Copy link
Contributor Author

ajkr commented Apr 3, 2020

edit: this problem is fixed.

huh, after ~30 minutes stress test failed. not sure yet if related.

$ python ./tools/db_crashtest.py blackbox --simple --max_key=1000000 --value_size_mult=33 --write_buffer_size=1048576 --target_file_size_base=1048576 --max_bytes_for_level_base=4194304
...
***Iterator diverged from control iterator which has value 000000000000270F000000000000012B00000000000002B1 total_order_seek: 0 auto_prefix_mode: 0 S 00000000000022D700000000000001027878 PPNPNPNNNP; total_order_seek: 0 auto_prefix_mode: 0 STL PPPNNNN***

@facebook-github-bot
Copy link
Contributor

@ajkr has updated the pull request. Re-import the pull request

Copy link
Contributor

@facebook-github-bot facebook-github-bot left a comment

Choose a reason for hiding this comment

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

@ajkr has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.

@ajkr ajkr changed the title save a key comparison in DataBlockIter::Seek() [wip] save a key comparison in DataBlockIter::Seek() Apr 3, 2020
@facebook-github-bot
Copy link
Contributor

@ajkr has updated the pull request. Re-import the pull request

@facebook-github-bot
Copy link
Contributor

@ajkr has updated the pull request. Re-import the pull request

@ajkr
Copy link
Contributor Author

ajkr commented Apr 4, 2020

alright, known problems are fixed so ready for review.

@ajkr ajkr changed the title [wip] save a key comparison in DataBlockIter::Seek() save a key comparison in DataBlockIter::Seek() Apr 4, 2020
Copy link
Contributor

@facebook-github-bot facebook-github-bot left a comment

Choose a reason for hiding this comment

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

@ajkr has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.

@facebook-github-bot
Copy link
Contributor

@ajkr has updated the pull request. Re-import the pull request

@ajkr ajkr changed the title save a key comparison in DataBlockIter::Seek() save a key comparison in delta-encoded data block seeks Apr 6, 2020
@facebook-github-bot
Copy link
Contributor

@ajkr has updated the pull request. Re-import the pull request

Copy link
Contributor

@facebook-github-bot facebook-github-bot left a comment

Choose a reason for hiding this comment

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

@ajkr has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.

@ajkr ajkr requested a review from siying April 6, 2020 18:12
@facebook-github-bot
Copy link
Contributor

@ajkr has updated the pull request. Re-import the pull request

@ajkr ajkr changed the title save a key comparison in delta-encoded data block seeks save a key comparison in block seeks Apr 11, 2020
@facebook-github-bot
Copy link
Contributor

@ajkr has updated the pull request. Re-import the pull request

@facebook-github-bot
Copy link
Contributor

@ajkr has updated the pull request. Re-import the pull request

Copy link
Contributor

@facebook-github-bot facebook-github-bot left a comment

Choose a reason for hiding this comment

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

@ajkr has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.

@ajkr ajkr force-pushed the optimize-key-comparison branch from 3302eeb to 50f890b Compare June 8, 2020 19:46
@facebook-github-bot
Copy link
Contributor

@ajkr has updated the pull request. Re-import the pull request

table/block_based/block.cc Show resolved Hide resolved
table/block_based/block.h Outdated Show resolved Hide resolved
ParseNextDataKey<DecodeEntry>();
}
} else {
SeekToRestartPoint(index - 1);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done. I also redid the BinarySeek() to avoid changing the binary search. The number of key comparisons saved lessened as a result, but I am fine with leaving those for a future PR..

Copy link
Contributor Author

@ajkr ajkr left a comment

Choose a reason for hiding this comment

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

couple explanatory comments

@ajkr ajkr force-pushed the optimize-key-comparison branch from 50f890b to c55640a Compare June 8, 2020 19:58
@facebook-github-bot
Copy link
Contributor

@ajkr has updated the pull request. Re-import the pull request

Copy link
Contributor

@facebook-github-bot facebook-github-bot left a comment

Choose a reason for hiding this comment

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

@ajkr has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.

Copy link
Contributor

@pdillinger pdillinger left a comment

Choose a reason for hiding this comment

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

I like this. Some suggestions for readability, but good.

Wouldn't hurt to have another set of eyes on this for correctness.

table/block_based/block.cc Outdated Show resolved Hide resolved
table/block_based/block.cc Outdated Show resolved Hide resolved
@pdillinger
Copy link
Contributor

MacOS compilation failure

Copy link
Contributor Author

@ajkr ajkr left a comment

Choose a reason for hiding this comment

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

MacOS compilation failure

Fixed (I think).

Thanks for the review!

table/block_based/block.cc Outdated Show resolved Hide resolved
table/block_based/block.cc Outdated Show resolved Hide resolved
@ajkr ajkr force-pushed the optimize-key-comparison branch from c55640a to 7f6c018 Compare June 9, 2020 20:54
@facebook-github-bot
Copy link
Contributor

@ajkr has updated the pull request. Re-import the pull request

Copy link
Contributor

@facebook-github-bot facebook-github-bot left a comment

Choose a reason for hiding this comment

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

@ajkr has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.

Copy link
Contributor

@anand1976 anand1976 left a comment

Choose a reason for hiding this comment

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

LGTM! Just a few nits and suggestions.

const Comparator* comp) {
// Linear search (within restart block) for first key >= target
SeekToRestartPoint(index);
Next();
Copy link
Contributor

Choose a reason for hiding this comment

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

A comment here might help. It took me a little while to figure out that this Next() actually doesn't advance to the next key, but just ends up decoding the key at the restart point we seek'd to.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agree, done.

*index = left;
if (*index == 0) {
// Special case as we land at zero as long as restart key at index 1 is >=
Copy link
Contributor

Choose a reason for hiding this comment

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

We land at 0 if restart key at index 1 > "target", right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Right, done.

@@ -393,6 +386,7 @@ void IndexBlockIter::Seek(const Slice& target) {
}
status_ = Status::OK();
uint32_t index = 0;
bool is_index_key_result = false;
Copy link
Contributor

Choose a reason for hiding this comment

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

Something like skip_linear_scan might be clearer.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done. Also renamed "ScanAfterBinarySeek" -> "FindKeyAfterBinarySeek" to make it fit in better.

max_offset = port::kMaxUint32;
}
while (true) {
Next();
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we just use ParseNextDataKey instead of Next and Valid?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's making use of polymorphism here -- IndexBlockIter::Next() calls ParseNextIndexKey() while DataBlockIter::Next() calls ParseNextDataKey().

ajkr added 3 commits June 10, 2020 11:58
This saves up to two key comparisons in block seeks. The first key
comparison saved is a redundant key comparison against the restart key
where the linear scan starts. This comparison is saved in all cases
except when the found key is in the first restart interval. The
second key comparison saved is a redundant key comparison against the
restart key where the linear scan ends. This is only saved in cases
where all keys in the restart interval are less than the target
(probability roughly `1/restart_interval`).

Test Plan:

ran readrandom with mostly default settings and counted key comparisons
using `PerfContext`.

before: `user_key_comparison_count = 30370310`
after: `user_key_comparison_count = 28881965`

setup command:

```
$ TEST_TMPDIR=/dev/shm/dbbench ./db_bench -benchmarks=fillrandom,compact -write_buffer_size=1048576 -target_file_size_base=1048576 -max_bytes_for_level_base=4194304 -max_background_jobs=12 -level_compaction_dynamic_level_bytes=true -num=10000000
```

benchmark command:

```
$ TEST_TMPDIR=/dev/shm/dbbench/ ./db_bench -use_existing_db=true -benchmarks=readrandom -disable_auto_compactions=true -num=10000000 -compression_type=none -reads=1000000 -perf_level=3
```
Copy link
Contributor Author

@ajkr ajkr left a comment

Choose a reason for hiding this comment

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

Thanks for the review! Addressed the comments.

@@ -393,6 +386,7 @@ void IndexBlockIter::Seek(const Slice& target) {
}
status_ = Status::OK();
uint32_t index = 0;
bool is_index_key_result = false;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done. Also renamed "ScanAfterBinarySeek" -> "FindKeyAfterBinarySeek" to make it fit in better.

const Comparator* comp) {
// Linear search (within restart block) for first key >= target
SeekToRestartPoint(index);
Next();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agree, done.

max_offset = port::kMaxUint32;
}
while (true) {
Next();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's making use of polymorphism here -- IndexBlockIter::Next() calls ParseNextIndexKey() while DataBlockIter::Next() calls ParseNextDataKey().

*index = left;
if (*index == 0) {
// Special case as we land at zero as long as restart key at index 1 is >=
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Right, done.

@facebook-github-bot
Copy link
Contributor

@ajkr has updated the pull request. Re-import the pull request

Copy link
Contributor

@facebook-github-bot facebook-github-bot left a comment

Choose a reason for hiding this comment

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

@ajkr has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.

@facebook-github-bot
Copy link
Contributor

@ajkr merged this pull request in e6be168.

facebook-github-bot pushed a commit that referenced this pull request Jul 9, 2020
Summary:
This is a followup to #6646. In that PR, for simplicity I just appended a comparison against the 0th restart key in case `BinarySeek()`'s binary search landed at index 0. As a result there were `2/(N+1) + log_2(N)` key comparisons. This PR does it differently. Now we expand the binary search range by one so it also covers the case where target is at or before the restart key at index 0. As a result, it involves `log_2(N+1)` key comparisons.

Pull Request resolved: #7068

Test Plan:
ran readrandom with mostly default settings and counted key comparisons
using `PerfContext`.

before: `user_key_comparison_count = 28881965`
after: `user_key_comparison_count = 27823245`

setup command:

```
$ TEST_TMPDIR=/dev/shm/dbbench ./db_bench -benchmarks=fillrandom,compact -write_buffer_size=1048576 -target_file_size_base=1048576 -max_bytes_for_level_base=4194304 -max_background_jobs=12 -level_compaction_dynamic_level_bytes=true -num=10000000
```

benchmark command:

```
$ TEST_TMPDIR=/dev/shm/dbbench/ ./db_bench -use_existing_db=true -benchmarks=readrandom -disable_auto_compactions=true -num=10000000 -compression_type=none -reads=1000000 -perf_level=3
```

Reviewed By: anand1976

Differential Revision: D22357032

Pulled By: ajkr

fbshipit-source-id: 8b01e9c1c2a4e9d02fc9dfe16c1cc0327f8bdf24
roghnin pushed a commit to roghnin/rocksdb that referenced this pull request Jul 9, 2020
Summary:
This is a followup to facebook#6646. In that PR, for simplicity I just appended a comparison against the 0th restart key in case `BinarySeek()`'s binary search landed at index 0. As a result there were `2/(N+1) + log_2(N)` key comparisons. This PR does it differently. Now we expand the binary search range by one so it also covers the case where target is at or before the restart key at index 0. As a result, it involves `log_2(N+1)` key comparisons.

Pull Request resolved: facebook#7068

Test Plan:
ran readrandom with mostly default settings and counted key comparisons
using `PerfContext`.

before: `user_key_comparison_count = 28881965`
after: `user_key_comparison_count = 27823245`

setup command:

```
$ TEST_TMPDIR=/dev/shm/dbbench ./db_bench -benchmarks=fillrandom,compact -write_buffer_size=1048576 -target_file_size_base=1048576 -max_bytes_for_level_base=4194304 -max_background_jobs=12 -level_compaction_dynamic_level_bytes=true -num=10000000
```

benchmark command:

```
$ TEST_TMPDIR=/dev/shm/dbbench/ ./db_bench -use_existing_db=true -benchmarks=readrandom -disable_auto_compactions=true -num=10000000 -compression_type=none -reads=1000000 -perf_level=3
```

Reviewed By: anand1976

Differential Revision: D22357032

Pulled By: ajkr

fbshipit-source-id: 8b01e9c1c2a4e9d02fc9dfe16c1cc0327f8bdf24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants