-
Notifications
You must be signed in to change notification settings - Fork 472
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
HrangebyLex
supports specify intervals
#1120
Changes from 16 commits
4044c05
cd7f46d
1c9e289
7be715e
ee9a2fe
4be2812
5d743ea
3566014
f51b6d7
a2a48d9
3cf648e
d47b335
4b4ac09
4c6fb4b
bfd774d
6dc81ad
b027d43
850a1c8
3fe6c40
8b8485d
a2f53a8
5073fad
427f816
581597d
644298b
37bc82b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -276,37 +276,65 @@ rocksdb::Status Hash::MSet(const Slice &user_key, const std::vector<FieldValue> | |
return storage_->Write(storage_->DefaultWriteOptions(), &batch); | ||
} | ||
|
||
rocksdb::Status Hash::Range(const Slice &user_key, const Slice &start, const Slice &stop, int64_t limit, | ||
std::vector<FieldValue> *field_values) { | ||
rocksdb::Status Hash::RangeByLex(const Slice &user_key, const HashRangeSpec &spec, | ||
std::vector<FieldValue> *field_values) { | ||
field_values->clear(); | ||
if (start.compare(stop) >= 0 || limit <= 0) { | ||
if (spec.count == 0) { | ||
return rocksdb::Status::OK(); | ||
} | ||
std::string ns_key; | ||
AppendNamespacePrefix(user_key, &ns_key); | ||
HashMetadata metadata(false); | ||
rocksdb::Status s = GetMetadata(ns_key, &metadata); | ||
if (!s.ok()) return s.IsNotFound() ? rocksdb::Status::OK() : s; | ||
limit = std::min(static_cast<int64_t>(metadata.size), limit); | ||
std::string start_key, stop_key; | ||
InternalKey(ns_key, start, metadata.version, storage_->IsSlotIdEncoded()).Encode(&start_key); | ||
InternalKey(ns_key, stop, metadata.version, storage_->IsSlotIdEncoded()).Encode(&stop_key); | ||
|
||
std::string start_member = spec.reversed ? spec.max : spec.min; | ||
std::string start_key, prefix_key, next_version_prefix_key; | ||
InternalKey(ns_key, start_member, metadata.version, storage_->IsSlotIdEncoded()).Encode(&start_key); | ||
InternalKey(ns_key, "", metadata.version, storage_->IsSlotIdEncoded()).Encode(&prefix_key); | ||
InternalKey(ns_key, "", metadata.version + 1, storage_->IsSlotIdEncoded()).Encode(&next_version_prefix_key); | ||
rocksdb::ReadOptions read_options; | ||
LatestSnapShot ss(db_); | ||
read_options.snapshot = ss.GetSnapShot(); | ||
rocksdb::Slice upper_bound(stop_key); | ||
rocksdb::Slice upper_bound(next_version_prefix_key); | ||
read_options.iterate_upper_bound = &upper_bound; | ||
rocksdb::Slice lower_bound(prefix_key); | ||
read_options.iterate_lower_bound = &lower_bound; | ||
read_options.fill_cache = false; | ||
|
||
auto iter = DBUtil::UniqueIterator(db_, read_options); | ||
iter->Seek(start_key); | ||
for (int64_t i = 0; iter->Valid() && i <= limit - 1; ++i) { | ||
if (!spec.reversed) { | ||
iter->Seek(start_key); | ||
} else { | ||
if (spec.max_infinite) { | ||
iter->SeekToLast(); | ||
} else { | ||
iter->SeekForPrev(start_key); | ||
} | ||
} | ||
int64_t pos = 0; | ||
for (; iter->Valid() && iter->key().starts_with(prefix_key); (!spec.reversed ? iter->Next() : iter->Prev())) { | ||
FieldValue tmp_field_value; | ||
InternalKey ikey(iter->key(), storage_->IsSlotIdEncoded()); | ||
if (spec.reversed) { | ||
if (ikey.GetSubKey().ToString() < spec.min || (spec.minex && ikey.GetSubKey().ToString() == spec.min)) { | ||
break; | ||
} | ||
if ((spec.maxex && ikey.GetSubKey().ToString() == spec.max) || | ||
(!spec.max_infinite && ikey.GetSubKey().ToString() > spec.max)) { | ||
continue; | ||
} | ||
} else { | ||
if (spec.minex && ikey.GetSubKey().ToString() == spec.min) continue; // the min member was exclusive | ||
if ((spec.maxex && ikey.GetSubKey().ToString() == spec.max) || | ||
(!spec.max_infinite && ikey.GetSubKey().ToString() > spec.max)) | ||
break; | ||
} | ||
if (spec.offset >= 0 && pos++ < spec.offset) continue; | ||
tmp_field_value.field = ikey.GetSubKey().ToString(); | ||
tmp_field_value.value = iter->value().ToString(); | ||
field_values->emplace_back(tmp_field_value); | ||
iter->Next(); | ||
if (spec.count > 0 && field_values && field_values->size() >= static_cast<unsigned>(spec.count)) break; | ||
} | ||
return rocksdb::Status::OK(); | ||
} | ||
|
@@ -355,4 +383,36 @@ rocksdb::Status Hash::Scan(const Slice &user_key, const std::string &cursor, uin | |
return SubKeyScanner::Scan(kRedisHash, user_key, cursor, limit, field_prefix, fields, values); | ||
} | ||
|
||
Status Hash::ParseRangeLexSpec(const std::string &min, const std::string &max, HashRangeSpec *spec) { | ||
tanruixiang marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can merge these same structure and methods of HashRangeSpec and ZRangeSpec in next PR. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why not this pr, i don't think we should import different function to deal with similar things There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have no strong opinion for this. Could you merge these structures and functions in this PR? @tanruixiang There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Ok. Sorry to have missed this comment. |
||
if (min == "+" || max == "-") { | ||
return Status(Status::NotOK, "min > max"); | ||
} | ||
|
||
if (min == "-") { | ||
spec->min = ""; | ||
} else { | ||
if (min[0] == '(') { | ||
spec->minex = true; | ||
} else if (min[0] == '[') { | ||
spec->minex = false; | ||
} else { | ||
return Status(Status::NotOK, "the min is illegal"); | ||
} | ||
spec->min = min.substr(1); | ||
} | ||
|
||
if (max == "+") { | ||
spec->max_infinite = true; | ||
} else { | ||
if (max[0] == '(') { | ||
spec->maxex = true; | ||
} else if (max[0] == '[') { | ||
spec->maxex = false; | ||
} else { | ||
return Status(Status::NotOK, "the max is illegal"); | ||
} | ||
spec->max = max.substr(1); | ||
} | ||
return Status::OK(); | ||
} | ||
} // namespace Redis |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why support
REV
option?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be aligned with zrange and makes sense, for example if you need to take the largest data.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
About aligning zrange I will deal with it in the new pr.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think
hrangebylex
is enough currently since i heard there is such a demand. Developers may not be used to thathash
support range operations, we can implement when someone wants it, WDYT?