* namespace".
*/
static int get_obj_vals(cls_method_context_t hctx,
- const string& start,
- const string& filter_prefix,
+ const std::string& start,
+ const std::string& filter_prefix,
int num_entries,
- map<string, bufferlist> *pkeys,
+ std::map<std::string, bufferlist> *pkeys,
bool *pmore)
{
int ret = cls_cxx_map_get_vals(hctx, start, filter_prefix,
return 0;
}
- auto last_element = pkeys->rbegin();
+ auto last_element = pkeys->crbegin();
if ((unsigned char)last_element->first[0] < BI_PREFIX_CHAR) {
/* if the first character of the last entry is less than the
* prefix then all entries must preceed the "ugly namespace" and
return 0;
}
- auto first_element = pkeys->begin();
+ auto first_element = pkeys->cbegin();
if ((unsigned char)first_element->first[0] > BI_PREFIX_CHAR) {
- /* the first character of the last entry is in or after the "ugly
- * namespace", so if the first character of the first entry
- * follows the "ugly namespace" then all entries do and we're done
+ /* if the first character of the first entry is after the "ugly
+ * namespace" then all entries must follow the "ugly namespace"
+ * then all entries do and we're done
*/
return 0;
}
* outside the "ugly namespace"
*/
- auto comp = [](const pair<string, bufferlist>& l, const string &r) {
+ auto comp = [](const pair<std::string, bufferlist>& l, const std::string &r) {
return l.first < r;
};
- string new_start = {static_cast<char>(BI_PREFIX_CHAR + 1)};
+ std::string new_start = {static_cast<char>(BI_PREFIX_CHAR + 1)};
auto lower = pkeys->lower_bound(string{static_cast<char>(BI_PREFIX_CHAR)});
auto upper = std::lower_bound(lower, pkeys->end(), new_start, comp);
return 0;
}
- if (pkeys->size() && new_start < pkeys->rbegin()->first) {
+ if (pkeys->size() && new_start < pkeys->crbegin()->first) {
new_start = pkeys->rbegin()->first;
}
- map<string, bufferlist> new_keys;
+ std::map<std::string, bufferlist> new_keys;
/* now get some more keys */
ret = cls_cxx_map_get_vals(hctx, new_start, filter_prefix,
return rc;
}
- string start_after_key; // key that we can start listing at, one of a)
- // sent in by caller, b) last item visited, or
- // c) when delimiter present, a key that will
- // move past the subdirectory
- encode_list_index_key(hctx, op.start_obj, &start_after_key);
+ // some calls just want the header and request 0 entries
+ if (op.num_entries <= 0) {
+ ret.is_truncated = false;
+ encode(ret, *out);
+ return 0;
+ }
+
+ // key that we can start listing at, one of a) sent in by caller, b)
+ // last item visited, or c) when delimiter present, a key that will
+ // move past the subdirectory
+ std::string start_after_omap_key;
+ encode_list_index_key(hctx, op.start_obj, &start_after_omap_key);
+
+ // this is set whenenver start_after_omap_key is set to keep them in
+ // sync since this will be the returned marker when a marker is
+ // returned
+ cls_rgw_obj_key start_after_entry_key;
+
+ // last key stored in result, so if we have to call get_obj_vals
+ // multiple times, we do not add the overlap to result
+ std::string prev_omap_key;
- string previous_key; // last key stored in result, so if we have to
- // call get_obj_vals multiple times, we do not
- // add the overlap to result
- string previous_prefix_key; // last prefix_key stored in result, so
- // we can skip over entries with the
- // same prefix_key
+ // last prefix_key stored in result, so we can skip over entries
+ // with the same prefix_key
+ std::string prev_prefix_omap_key;
bool done = false; // whether we need to keep calling get_obj_vals
bool more = true; // output parameter of get_obj_vals
bool has_delimiter = !op.delimiter.empty();
if (has_delimiter &&
- start_after_key > op.filter_prefix &&
- boost::algorithm::ends_with(start_after_key, op.delimiter)) {
+ start_after_omap_key > op.filter_prefix &&
+ boost::algorithm::ends_with(start_after_omap_key, op.delimiter)) {
// advance past all subdirectory entries if we start after a
// subdirectory
- start_after_key = cls_rgw_after_delim(start_after_key);
+ start_after_omap_key = cls_rgw_after_delim(start_after_omap_key);
}
for (int attempt = 0;
!done &&
name_entry_map.size() < op.num_entries;
++attempt) {
- map<string, bufferlist> keys;
- rc = get_obj_vals(hctx, start_after_key, op.filter_prefix,
+ std::map<std::string, bufferlist> keys;
+
+ // note: get_obj_vals skips past the "ugly namespace" (i.e.,
+ // entries that start with the BI_PREFIX_CHAR), so no need to
+ // check for such entries
+ rc = get_obj_vals(hctx, start_after_omap_key, op.filter_prefix,
op.num_entries - name_entry_map.size(),
&keys, &more);
if (rc < 0) {
done = keys.empty();
for (auto kiter = keys.cbegin(); kiter != keys.cend(); ++kiter) {
- if (!bi_is_plain_entry(kiter->first)) {
- // we're done if we walked off the end of the objects area of
- // the bucket index
- done = true;
- break;
- }
-
rgw_bucket_dir_entry entry;
try {
const bufferlist& entrybl = kiter->second;
return -EINVAL;
}
- start_after_key = kiter->first;
+ start_after_omap_key = kiter->first;
+ start_after_entry_key = entry.key;
CLS_LOG(20, "%s: working on key=%s len=%zu",
__func__, kiter->first.c_str(), kiter->first.size());
string prefix_key =
key.name.substr(0, delim_pos + op.delimiter.length());
- if (prefix_key == previous_prefix_key) {
+ if (prefix_key == prev_prefix_omap_key) {
continue; // we've already added this;
} else {
- previous_prefix_key = prefix_key;
+ prev_prefix_omap_key = prefix_key;
}
if (name_entry_map.size() < op.num_entries) {
// make sure that if this is the last item added to the
// result from this call to get_obj_vals, the next call will
// skip past rest of "subdirectory"
- start_after_key = cls_rgw_after_delim(prefix_key);
+ start_after_omap_key = cls_rgw_after_delim(prefix_key);
+ start_after_entry_key.set(start_after_omap_key);
- // advance to past this subdirectory, but then back up one,
+ // advance past this subdirectory, but then back up one,
// so the loop increment will put us in the right place
- kiter = keys.lower_bound(start_after_key);
+ kiter = keys.lower_bound(start_after_omap_key);
--kiter;
continue;
}
if (name_entry_map.size() < op.num_entries &&
- kiter->first != previous_key) {
+ kiter->first != prev_omap_key) {
name_entry_map[kiter->first] = entry;
- previous_key = kiter->first;
+ prev_omap_key = kiter->first;
CLS_LOG(20, "%s: got object entry %s[%s] num entries=%d\n",
__func__, key.name.c_str(), key.instance.c_str(),
int(name_entry_map.size()));
} // for (int attempt...
ret.is_truncated = more && !done;
+ if (ret.is_truncated) {
+ ret.marker = start_after_entry_key;
+ }
CLS_LOG(20, "%s: normal exit returning %ld entries, is_truncated=%d\n",
__func__, ret.dir.m.size(), ret.is_truncated);
encode(ret, *out);
- return 0;
+
+ if (ret.is_truncated && name_entry_map.size() == 0) {
+ CLS_LOG(5, "%s: returning value RGWBIAdvanceAndRetryError\n", __func__);
+ return RGWBIAdvanceAndRetryError;
+ } else {
+ return 0;
+ }
} // rgw_bucket_list
+
static int check_index(cls_method_context_t hctx,
rgw_bucket_dir_header *existing_header,
rgw_bucket_dir_header *calc_header)