prefix = s->info.args.get("prefix");
marker = s->info.args.get("marker");
end_marker = s->info.args.get("end_marker");
+ wants_reversed = s->info.args.exists("reverse");
string limit_str = s->info.args.get("limit");
if (!limit_str.empty()) {
}
}
+void RGWListBuckets_ObjStore_SWIFT::handle_listing_chunk(RGWUserBuckets& buckets)
+{
+ if (wants_reversed) {
+ /* Just store in the reversal buffer. Its content will be handled later,
+ * in send_response_end(). */
+ reverse_buffer.emplace(std::begin(reverse_buffer), std::move(buckets));
+ } else {
+ return send_response_data(buckets);
+ }
+}
+
void RGWListBuckets_ObjStore_SWIFT::send_response_data(RGWUserBuckets& buckets)
{
if (! sent_data) {
for (auto iter = m.lower_bound(prefix);
iter != m.end() && boost::algorithm::starts_with(iter->first, prefix);
++iter) {
- const RGWBucketEnt& obj = iter->second;
+ dump_bucket_entry(iter->second);
+ }
+}
- s->formatter->open_object_section("container");
- s->formatter->dump_string("name", obj.bucket.name);
- if (need_stats) {
- s->formatter->dump_int("count", obj.count);
- s->formatter->dump_int("bytes", obj.size);
- }
- s->formatter->close_section();
- if (! s->cct->_conf->rgw_swift_enforce_content_length) {
- rgw_flush_formatter(s, s->formatter);
- }
+void RGWListBuckets_ObjStore_SWIFT::dump_bucket_entry(const RGWBucketEnt& obj)
+{
+ s->formatter->open_object_section("container");
+ s->formatter->dump_string("name", obj.bucket.name);
+
+ if (need_stats) {
+ s->formatter->dump_int("count", obj.count);
+ s->formatter->dump_int("bytes", obj.size);
+ }
+
+ s->formatter->close_section();
+
+ if (! s->cct->_conf->rgw_swift_enforce_content_length) {
+ rgw_flush_formatter(s, s->formatter);
+ }
+}
+
+void RGWListBuckets_ObjStore_SWIFT::send_response_data_reversed(RGWUserBuckets& buckets)
+{
+ if (! sent_data) {
+ return;
+ }
+
+ /* Take care of the prefix parameter of Swift API. There is no business
+ * in applying the filter earlier as we really need to go through all
+ * entries regardless of it (the headers like X-Account-Container-Count
+ * aren't affected by specifying prefix). */
+ std::map<std::string, RGWBucketEnt>& m = buckets.get_buckets();
+
+ auto iter = m.rbegin();
+ for (/* initialized above */;
+ iter != m.rend() && !boost::algorithm::starts_with(iter->first, prefix);
+ ++iter) {
+ /* NOP */;
+ }
+
+ for (/* iter carried */;
+ iter != m.rend() && boost::algorithm::starts_with(iter->first, prefix);
+ ++iter) {
+ dump_bucket_entry(iter->second);
}
}
void RGWListBuckets_ObjStore_SWIFT::send_response_end()
{
+ if (wants_reversed) {
+ for (auto& buckets : reverse_buffer) {
+ send_response_data_reversed(buckets);
+ }
+ }
+
if (sent_data) {
s->formatter->close_section();
}
user_quota,
static_cast<RGWAccessControlPolicy_SWIFTAcct&>(*s->user_acl));
dump_errno(s);
- end_header(s, NULL, NULL, s->formatter->get_len(), true);
+ end_header(s, nullptr, nullptr, s->formatter->get_len(), true);
}
if (sent_data || s->cct->_conf->rgw_swift_enforce_content_length) {
class RGWListBuckets_ObjStore_SWIFT : public RGWListBuckets_ObjStore {
bool need_stats;
+ bool wants_reversed;
std::string prefix;
+ std::vector<RGWUserBuckets> reverse_buffer;
uint64_t get_default_max() const override {
return 0;
}
+
public:
- RGWListBuckets_ObjStore_SWIFT() : need_stats(true) {}
+ RGWListBuckets_ObjStore_SWIFT()
+ : need_stats(true),
+ wants_reversed(false) {
+ }
~RGWListBuckets_ObjStore_SWIFT() override {}
int get_params() override;
+ void handle_listing_chunk(RGWUserBuckets& buckets) override;
void send_response_begin(bool has_buckets) override;
void send_response_data(RGWUserBuckets& buckets) override;
+ void send_response_data_reversed(RGWUserBuckets& buckets);
+ void dump_bucket_entry(const RGWBucketEnt& obj);
void send_response_end() override;
bool should_get_stats() override { return need_stats; }