*
* @param omap_root: omap btree root information
* @param t: current transaction
- * @param start: nullopt sorts before any string, behavior
- * based on config.inclusive
+ * @param first: range start, nullopt sorts before any string,
+ * behavior based on config.inclusive,
+ * must alive during the call
+ * @param last: range end, nullopt sorts after any string,
+ * behavior based on config.inclusive,
+ * must alive during the call
* @param config: see below for params
* @retval listed key->value and bool indicating complete
*/
virtual omap_list_ret omap_list(
const omap_root_t &omap_root,
Transaction &t,
- const std::optional<std::string> &start,
+ const std::optional<std::string> &first,
+ const std::optional<std::string> &last,
omap_list_config_t config = omap_list_config_t()) = 0;
/**
BtreeOMapManager::omap_list(
const omap_root_t &omap_root,
Transaction &t,
- const std::optional<std::string> &start,
+ const std::optional<std::string> &first,
+ const std::optional<std::string> &last,
omap_list_config_t config)
{
LOG_PREFIX(BtreeOMapManager::omap_list);
- if (start) {
- DEBUGT("{}, start: {}", t, omap_root, *start);
+ if (first && last) {
+ DEBUGT("{}, first: {}, last: {}", t, omap_root, *first, *last);
+ assert(last >= first);
+ } else if (first) {
+ DEBUGT("{}, first: {}", t, omap_root, *first);
+ } else if (last) {
+ DEBUGT("{}, last: {}", t, omap_root, *last);
} else {
DEBUGT("{}", t, omap_root);
}
+
return get_omap_root(
get_omap_context(t, omap_root.hint),
omap_root
- ).si_then([this, config, &t, &start, &omap_root](auto extent) {
+ ).si_then([this, config, &t, &first, &last, &omap_root](auto extent) {
return extent->list(
get_omap_context(t, omap_root.hint),
- start,
+ first,
+ last,
config);
});
}
omap_list_ret omap_list(
const omap_root_t &omap_root,
Transaction &t,
- const std::optional<std::string> &start,
+ const std::optional<std::string> &first,
+ const std::optional<std::string> &last,
omap_list_config_t config = omap_list_config_t()) final;
omap_clear_ret omap_clear(
using list_ret = OMapManager::omap_list_ret;
virtual list_ret list(
omap_context_t oc,
- const std::optional<std::string> &start,
+ const std::optional<std::string> &first,
+ const std::optional<std::string> &last,
omap_list_config_t config) = 0;
using clear_iertr = base_iertr;
OMapInnerNode::list_ret
OMapInnerNode::list(
omap_context_t oc,
- const std::optional<std::string> &start,
+ const std::optional<std::string> &first,
+ const std::optional<std::string> &last,
omap_list_config_t config)
{
LOG_PREFIX(OMapInnerNode::list);
- if (start) {
- DEBUGT("start={}, this: {}", oc.t, *start, *this);
+ if (first && last) {
+ DEBUGT("first: {}, last: {}, this: {}", oc.t, *first, *last, *this);
+ assert(*first <= *last);
+ } else if (first) {
+ DEBUGT("first: {}, this: {}", oc.t, *first, *this);
+ } else if (last) {
+ DEBUGT("last: {}, this: {}", oc.t, *last, *this);
} else {
DEBUGT("this: {}", oc.t, *this);
}
- auto child_iter = start ?
- get_containing_child(*start) :
+ auto first_iter = first ?
+ get_containing_child(*first) :
iter_cbegin();
- assert(child_iter != iter_cend());
+ auto last_iter = last ?
+ get_containing_child(*last) + 1:
+ iter_cend();
+ assert(first_iter != iter_cend());
return seastar::do_with(
- child_iter,
- iter_cend(),
+ first_iter,
+ last_iter,
+ iter_t(first_iter),
list_bare_ret(false, {}),
- true,
- start,
- [this, oc, config](
- auto &biter,
- auto &eiter,
- auto &ret,
- bool &first_entry,
- auto &start)
+ [this, &first, &last, oc, config](
+ auto &fiter,
+ auto &liter,
+ auto &iter,
+ auto &ret)
{
auto &complete = std::get<0>(ret);
auto &result = std::get<1>(ret);
return trans_intr::repeat(
- [&, config, oc, this]() -> list_iertr::future<seastar::stop_iteration> {
- if (biter == eiter || result.size() == config.max_result_size) {
- complete = biter == eiter;
- return list_iertr::make_ready_future<seastar::stop_iteration>(
- seastar::stop_iteration::yes);
- }
- auto laddr = biter->get_val();
- return omap_load_extent(
- oc, laddr,
- get_meta().depth - 1
- ).si_then([&, config, oc] (auto &&extent) {
+ [&, config, oc, this]() -> list_iertr::future<seastar::stop_iteration>
+ {
+ if (iter == liter || result.size() == config.max_result_size) {
+ complete = iter == liter;
+ return list_iertr::make_ready_future<seastar::stop_iteration>(
+ seastar::stop_iteration::yes);
+ }
+ auto laddr = iter->get_val();
+ return omap_load_extent(
+ oc, laddr,
+ get_meta().depth - 1
+ ).si_then([&, config, oc](auto &&extent) {
+ return seastar::do_with(
+ iter == fiter ? first : std::optional<std::string>(std::nullopt),
+ iter == liter - 1 ? last : std::optional<std::string>(std::nullopt),
+ [&result, extent = std::move(extent), config, oc](
+ auto &nfirst,
+ auto &nlast) {
return extent->list(
oc,
- first_entry ? start : std::nullopt,
- config.with_reduced_max(result.size())
- ).si_then([&, config](auto &&child_ret) mutable {
- boost::ignore_unused(config); // avoid clang warning;
- auto &[child_complete, child_result] = child_ret;
- if (result.size() && child_result.size()) {
- assert(child_result.begin()->first > result.rbegin()->first);
+ nfirst,
+ nlast,
+ config.with_reduced_max(result.size()));
+ }).si_then([&, config](auto &&child_ret) mutable {
+ boost::ignore_unused(config); // avoid clang warning;
+ auto &[child_complete, child_result] = child_ret;
+ if (result.size() && child_result.size()) {
+ assert(child_result.begin()->first > result.rbegin()->first);
+ }
+ if (child_result.size() && first && iter == fiter) {
+ if (config.inclusive) {
+ assert(child_result.begin()->first >= *first);
+ } else {
+ assert(child_result.begin()->first > *first);
}
- if (child_result.size() && start && first_entry) {
- if (config.inclusive) {
- assert(child_result.begin()->first >= *start);
- } else {
- assert(child_result.begin()->first > *start);
- }
+ }
+ if (child_result.size() && last && iter == liter - 1) {
+ auto biter = --(child_result.end());
+ if (config.inclusive) {
+ assert(biter->first <= *last);
+ } else {
+ assert(biter->first < *last);
}
- result.merge(std::move(child_result));
- ++biter;
- assert(child_complete || result.size() == config.max_result_size);
- first_entry = false;
- return list_iertr::make_ready_future<seastar::stop_iteration>(
- seastar::stop_iteration::no);
- });
- });
- }).si_then([&ret, ref = OMapNodeRef(this)] {
- return list_iertr::make_ready_future<list_bare_ret>(std::move(ret));
- });
+ }
+ result.merge(std::move(child_result));
+ ++iter;
+ assert(child_complete || result.size() == config.max_result_size);
+ return list_iertr::make_ready_future<seastar::stop_iteration>(
+ seastar::stop_iteration::no);
+ });
+ });
+ }).si_then([&ret, ref = OMapNodeRef(this)] {
+ return list_iertr::make_ready_future<list_bare_ret>(std::move(ret));
+ });
});
}
OMapLeafNode::list_ret
OMapLeafNode::list(
omap_context_t oc,
- const std::optional<std::string> &start,
+ const std::optional<std::string> &first,
+ const std::optional<std::string> &last,
omap_list_config_t config)
{
LOG_PREFIX(OMapLeafNode::list);
DEBUGT(
- "start {} max_result_size {} inclusive {}, this: {}",
+ "first {} last {} max_result_size {} inclusive {}, this: {}",
oc.t,
- start ? start->c_str() : "",
+ first ? first->c_str() : "",
+ last ? last->c_str() : "",
config.max_result_size,
config.inclusive,
*this
);
auto ret = list_bare_ret(false, {});
auto &[complete, result] = ret;
- auto iter = start ?
+ auto iter = first ?
(config.inclusive ?
- string_lower_bound(*start) :
- string_upper_bound(*start)) :
+ string_lower_bound(*first) :
+ string_upper_bound(*first)) :
iter_begin();
+ auto liter = last ?
+ (config.inclusive ?
+ string_upper_bound(*last) :
+ string_lower_bound(*last)) :
+ iter_end();
- for (; iter != iter_end() && result.size() < config.max_result_size; iter++) {
+ for (; iter != liter && result.size() < config.max_result_size; iter++) {
result.emplace(std::make_pair(iter->get_key(), iter->get_val()));
}
- complete = (iter == iter_end());
+ complete = (iter == liter);
return list_iertr::make_ready_future<list_bare_ret>(
std::move(ret));
list_ret list(
omap_context_t oc,
- const std::optional<std::string> &start,
+ const std::optional<std::string> &first,
+ const std::optional<std::string> &last,
omap_list_config_t config) final;
clear_ret clear(omap_context_t oc) final;
list_ret list(
omap_context_t oc,
- const std::optional<std::string> &start,
+ const std::optional<std::string> &first,
+ const std::optional<std::string> &last,
omap_list_config_t config) final;
clear_ret clear(
BtreeOMapManager(*transaction_manager),
root,
start,
- [&t, config](auto &manager, auto& root, auto& start) {
- return manager.omap_list(root, t, start, config);
- });
+ std::optional<std::string>(std::nullopt),
+ [&t, config](auto &manager, auto &root, auto &start, auto &end) {
+ return manager.omap_list(root, t, start, end, config);
+ });
}
SeaStore::omap_get_values_ret_t SeaStore::omap_list(
Transaction::src_t::READ,
"omap_list",
op_type_t::OMAP_LIST,
- [this, config, &start](auto &t, auto &onode) {
+ [this, config, start](auto &t, auto &onode) {
return _omap_list(
onode,
onode.get_layout().omap_root,
t, start, config
);
- });
+ });
}
SeaStore::omap_get_values_ret_t SeaStore::omap_get_values(
const ghobject_t &oid,
const std::optional<string> &start)
{
- return seastar::do_with(oid, start,
- [this, ch=std::move(ch)](auto& oid, auto& start) {
+ return seastar::do_with(
+ oid,
+ [this, start, ch=std::move(ch)](auto& oid) {
return omap_list(
ch, oid, start,
OMapManager::omap_list_config_t::with_inclusive(false));
void list(
const omap_root_t &omap_root,
Transaction &t,
- const std::optional<std::string> &start,
+ const std::optional<std::string> &first,
+ const std::optional<std::string> &last,
size_t max = 128,
bool inclusive = false) {
- if (start) {
- logger().debug("list on {}", *start);
+ if (first && last) {
+ logger().debug("list on {} ~ {}", *first, *last);
+ } else if (first) {
+ logger().debug("list on {} ~ end", *first);
+ } else if (last) {
+ logger().debug("list on start ~ {}", *last);
} else {
- logger().debug("list on start");
+ logger().debug("list on start ~ end");
}
auto config = OMapManager::omap_list_config_t::with_max(max);
auto [complete, results] = with_trans_intr(
t,
[&, this](auto &t) {
- return omap_manager->omap_list(omap_root, t, start, config);
+ return omap_manager->omap_list(omap_root, t, first, last, config);
}).unsafe_get0();
- test_omap_t::iterator it;
- if (start) {
+ test_omap_t::iterator it, lit;
+ if (first) {
it = config.inclusive ?
- test_omap_mappings.lower_bound(*start) :
- test_omap_mappings.upper_bound(*start);
+ test_omap_mappings.lower_bound(*first) :
+ test_omap_mappings.upper_bound(*first);
} else {
it = test_omap_mappings.begin();
}
+ if (last) {
+ lit = config.inclusive ?
+ test_omap_mappings.upper_bound(*last) :
+ test_omap_mappings.lower_bound(*last);
+ } else {
+ lit = test_omap_mappings.end();
+ }
+
for (auto &&[k, v]: results) {
EXPECT_NE(it, test_omap_mappings.end());
if (it == test_omap_mappings.end())
EXPECT_EQ(v, it->second);
it++;
}
- if (it == test_omap_mappings.end()) {
+ if (it == lit) {
EXPECT_TRUE(complete);
} else {
EXPECT_EQ(results.size(), max);
{
auto t = create_read_transaction();
- list(omap_root, *t, std::nullopt);
+ list(omap_root, *t, std::nullopt, std::nullopt);
}
{
auto t = create_read_transaction();
- list(omap_root, *t, temp, 100);
+ list(omap_root, *t, temp, std::nullopt, 100);
}
{
auto t = create_read_transaction();
- list(omap_root, *t, temp, 100, true);
+ list(omap_root, *t, temp, std::nullopt, 100, true);
}
{
{
auto t = create_read_transaction();
- list(omap_root, *t, temp, 10240);
+ list(omap_root, *t, temp, std::nullopt, 10240);
}
{
auto t = create_read_transaction();
- list(omap_root, *t, temp, 10240, true);
+ list(omap_root, *t, temp, std::nullopt, 10240, true);
}
{