Polish IterKey and use it in DBImpl::ProcessKeyValueCompaction()

Summary:
1. Polish IterKey a little bit.
2. Turn to use it in local parameter of current_user_key in DBImpl::ProcessKeyValueCompaction(). Our profile showing that DBImpl::ProcessKeyValueCompaction() has about 14% costs in std::string (the base including reading and writing data but excluding compaction filtering), which is higher than it should be. There are two std::string used in DBImpl::ProcessKeyValueCompaction(), compaction_filter_value and current_user_key and it's hard to distinguish the two.

Test Plan: make all check

Reviewers: haobo, ljin

Reviewed By: haobo

CC: igor, yhchiang, dhruba, leveldb

Differential Revision: https://reviews.facebook.net/D17613
main
sdong 11 years ago
parent dc55903293
commit df2a8b6a1a
  1. 20
      db/db_impl.cc
  2. 64
      db/dbformat.h

@ -2523,9 +2523,9 @@ Status DBImpl::ProcessKeyValueCompaction(
Status status; Status status;
std::string compaction_filter_value; std::string compaction_filter_value;
ParsedInternalKey ikey; ParsedInternalKey ikey;
std::string current_user_key; IterKey current_user_key;
bool has_current_user_key = false; bool has_current_user_key = false;
std::vector<char> delete_key; // for compaction filter IterKey delete_key;
SequenceNumber last_sequence_for_key __attribute__((unused)) = SequenceNumber last_sequence_for_key __attribute__((unused)) =
kMaxSequenceNumber; kMaxSequenceNumber;
SequenceNumber visible_in_snapshot = kMaxSequenceNumber; SequenceNumber visible_in_snapshot = kMaxSequenceNumber;
@ -2589,16 +2589,16 @@ Status DBImpl::ProcessKeyValueCompaction(
// Do not hide error keys // Do not hide error keys
// TODO: error key stays in db forever? Figure out the intention/rationale // TODO: error key stays in db forever? Figure out the intention/rationale
// v10 error v8 : we cannot hide v8 even though it's pretty obvious. // v10 error v8 : we cannot hide v8 even though it's pretty obvious.
current_user_key.clear(); current_user_key.Clear();
has_current_user_key = false; has_current_user_key = false;
last_sequence_for_key = kMaxSequenceNumber; last_sequence_for_key = kMaxSequenceNumber;
visible_in_snapshot = kMaxSequenceNumber; visible_in_snapshot = kMaxSequenceNumber;
} else { } else {
if (!has_current_user_key || if (!has_current_user_key ||
cfd->user_comparator()->Compare(ikey.user_key, cfd->user_comparator()->Compare(ikey.user_key,
Slice(current_user_key)) != 0) { current_user_key.GetKey()) != 0) {
// First occurrence of this user key // First occurrence of this user key
current_user_key.assign(ikey.user_key.data(), ikey.user_key.size()); current_user_key.SetUserKey(ikey.user_key);
has_current_user_key = true; has_current_user_key = true;
last_sequence_for_key = kMaxSequenceNumber; last_sequence_for_key = kMaxSequenceNumber;
visible_in_snapshot = kMaxSequenceNumber; visible_in_snapshot = kMaxSequenceNumber;
@ -2617,13 +2617,11 @@ Status DBImpl::ProcessKeyValueCompaction(
compact->compaction->level(), ikey.user_key, value, compact->compaction->level(), ikey.user_key, value,
&compaction_filter_value, &value_changed); &compaction_filter_value, &value_changed);
if (to_delete) { if (to_delete) {
// make a copy of the original key // make a copy of the original key and convert it to a delete
delete_key.assign(key.data(), key.data() + key.size()); delete_key.SetInternalKey(ExtractUserKey(key), ikey.sequence,
// convert it to a delete kTypeDeletion);
UpdateInternalKey(&delete_key[0], delete_key.size(),
ikey.sequence, kTypeDeletion);
// anchor the key again // anchor the key again
key = Slice(&delete_key[0], delete_key.size()); key = delete_key.GetKey();
// needed because ikey is backed by key // needed because ikey is backed by key
ParseInternalKey(key, &ikey); ParseInternalKey(key, &ikey);
// no value associated with delete // no value associated with delete

@ -242,47 +242,17 @@ class IterKey {
public: public:
IterKey() : key_(space_), buf_size_(sizeof(space_)), key_size_(0) {} IterKey() : key_(space_), buf_size_(sizeof(space_)), key_size_(0) {}
~IterKey() { Clear(); } ~IterKey() { ResetBuffer(); }
Slice GetKey() const { Slice GetKey() const { return Slice(key_, key_size_); }
if (key_ != nullptr) {
return Slice(key_, key_size_);
} else {
return Slice();
}
}
bool Valid() const { return key_ != nullptr; }
void Clear() {
if (key_ != nullptr && key_ != space_) {
delete[] key_;
}
key_ = space_;
buf_size_ = sizeof(buf_size_);
}
// Enlarge the buffer size if needed based on key_size. void Clear() { key_size_ = 0; }
// By default, static allocated buffer is used. Once there is a key
// larger than the static allocated buffer, another buffer is dynamically
// allocated, until a larger key buffer is requested. In that case, we
// reallocate buffer and delete the old one.
void EnlargeBufferIfNeeded(size_t key_size) {
// If size is smaller than buffer size, continue using current buffer,
// or the static allocated one, as default
if (key_size > buf_size_) {
// Need to enlarge the buffer.
Clear();
key_ = new char[key_size];
buf_size_ = key_size;
}
key_size_ = key_size;
}
void SetUserKey(const Slice& user_key) { void SetUserKey(const Slice& user_key) {
size_t size = user_key.size(); size_t size = user_key.size();
EnlargeBufferIfNeeded(size); EnlargeBufferIfNeeded(size);
memcpy(key_, user_key.data(), size); memcpy(key_, user_key.data(), size);
key_size_ = size;
} }
void SetInternalKey(const Slice& user_key, SequenceNumber s, void SetInternalKey(const Slice& user_key, SequenceNumber s,
@ -291,6 +261,7 @@ class IterKey {
EnlargeBufferIfNeeded(usize + sizeof(uint64_t)); EnlargeBufferIfNeeded(usize + sizeof(uint64_t));
memcpy(key_, user_key.data(), usize); memcpy(key_, user_key.data(), usize);
EncodeFixed64(key_ + usize, PackSequenceAndType(s, value_type)); EncodeFixed64(key_ + usize, PackSequenceAndType(s, value_type));
key_size_ = usize + sizeof(uint64_t);
} }
void SetInternalKey(const ParsedInternalKey& parsed_key) { void SetInternalKey(const ParsedInternalKey& parsed_key) {
@ -303,6 +274,31 @@ class IterKey {
size_t key_size_; size_t key_size_;
char space_[32]; // Avoid allocation for short keys char space_[32]; // Avoid allocation for short keys
void ResetBuffer() {
if (key_ != nullptr && key_ != space_) {
delete[] key_;
}
key_ = space_;
buf_size_ = sizeof(buf_size_);
key_size_ = 0;
}
// Enlarge the buffer size if needed based on key_size.
// By default, static allocated buffer is used. Once there is a key
// larger than the static allocated buffer, another buffer is dynamically
// allocated, until a larger key buffer is requested. In that case, we
// reallocate buffer and delete the old one.
void EnlargeBufferIfNeeded(size_t key_size) {
// If size is smaller than buffer size, continue using current buffer,
// or the static allocated one, as default
if (key_size > buf_size_) {
// Need to enlarge the buffer.
ResetBuffer();
key_ = new char[key_size];
buf_size_ = key_size;
}
}
// No copying allowed // No copying allowed
IterKey(const IterKey&) = delete; IterKey(const IterKey&) = delete;
void operator=(const IterKey&) = delete; void operator=(const IterKey&) = delete;

Loading…
Cancel
Save