in src/types/redis_hash.cc [298:353]
rocksdb::Status Hash::RangeByLex(engine::Context &ctx, const Slice &user_key, const RangeLexSpec &spec,
std::vector<FieldValue> *field_values) {
field_values->clear();
if (spec.count == 0) {
return rocksdb::Status::OK();
}
std::string ns_key = AppendNamespacePrefix(user_key);
HashMetadata metadata(false);
rocksdb::Status s = GetMetadata(ctx, ns_key, &metadata);
if (!s.ok()) return s.IsNotFound() ? rocksdb::Status::OK() : s;
std::string start_member = spec.reversed ? spec.max : spec.min;
std::string start_key = InternalKey(ns_key, start_member, metadata.version, storage_->IsSlotIdEncoded()).Encode();
std::string prefix_key = InternalKey(ns_key, "", metadata.version, storage_->IsSlotIdEncoded()).Encode();
std::string next_version_prefix_key =
InternalKey(ns_key, "", metadata.version + 1, storage_->IsSlotIdEncoded()).Encode();
rocksdb::ReadOptions read_options = ctx.DefaultScanOptions();
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;
auto iter = util::UniqueIterator(ctx, read_options);
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())) {
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;
field_values->emplace_back(ikey.GetSubKey().ToString(), iter->value().ToString());
if (spec.count > 0 && field_values->size() >= static_cast<unsigned>(spec.count)) break;
}
return rocksdb::Status::OK();
}