* Returns the list of trash spec entries registered in the rbd_trash
* object.
*
+ * Input:
+ * @param start_after which name to begin listing after
+ * (use the empty string to start at the beginning)
+ * @param max_return the maximum number of names to list
+ *
* Output:
* @param data the map between image id and trash spec info
*
*/
int trash_list(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
{
+ string start_after;
+ uint64_t max_return;
+
+ try {
+ bufferlist::iterator iter = in->begin();
+ ::decode(start_after, iter);
+ ::decode(max_return, iter);
+ } catch (const buffer::error &err) {
+ return -EINVAL;
+ }
+
map<string, cls::rbd::TrashImageSpec> data;
- string last_read = trash::image_key("");
- int max_read = RBD_MAX_KEYS_READ;
+ string last_read = trash::image_key(start_after);
CLS_LOG(20, "trash_get_images");
-
- do {
+ while (data.size() < max_return) {
map<string, bufferlist> raw_data;
+ int max_read = std::min<int32_t>(RBD_MAX_KEYS_READ,
+ max_return - data.size());
int r = cls_cxx_map_get_vals(hctx, last_read, trash::IMAGE_KEY_PREFIX,
max_read, &raw_data);
if (r < 0) {
- CLS_ERR("failed to read the vals off of disk: %s", cpp_strerror(r).c_str());
+ CLS_ERR("failed to read the vals off of disk: %s",
+ cpp_strerror(r).c_str());
return r;
}
if (raw_data.empty()) {
}
last_read = raw_data.rbegin()->first;
- } while (max_read);
+ }
::encode(data, *out);
-
return 0;
}
return ioctx->operate(RBD_TRASH, &op);
}
- void trash_list_start(librados::ObjectReadOperation *op)
+ void trash_list_start(librados::ObjectReadOperation *op,
+ const std::string &start, uint64_t max_return)
{
bufferlist bl;
+ ::encode(start, bl);
+ ::encode(max_return, bl);
op->exec("rbd", "trash_list", bl);
}
}
int trash_list(librados::IoCtx *ioctx,
+ const std::string &start, uint64_t max_return,
map<string, cls::rbd::TrashImageSpec> *entries)
{
librados::ObjectReadOperation op;
- trash_list_start(&op);
+ trash_list_start(&op, start, max_return);
bufferlist out_bl;
int r = ioctx->operate(RBD_TRASH, &op, &out_bl);
void trash_remove(librados::ObjectWriteOperation *op,
const std::string &id);
int trash_remove(librados::IoCtx *ioctx, const std::string &id);
- void trash_list_start(librados::ObjectReadOperation *op);
+ void trash_list_start(librados::ObjectReadOperation *op,
+ const std::string &start, uint64_t max_return);
int trash_list_finish(bufferlist::iterator *it,
map<string, cls::rbd::TrashImageSpec> *entries);
int trash_list(librados::IoCtx *ioctx,
+ const std::string &start, uint64_t max_return,
map<string, cls::rbd::TrashImageSpec> *entries);
void trash_get_start(librados::ObjectReadOperation *op,
const std::string &id);
CephContext *cct((CephContext *)io_ctx.cct());
ldout(cct, 20) << "trash_list " << &io_ctx << dendl;
- map<string, cls::rbd::TrashImageSpec> trash_entries;
- int r = cls_client::trash_list(&io_ctx, &trash_entries);
- if (r < 0) {
- if (r != -ENOENT) {
- lderr(cct) << "error listing rbd_trash entries: " << cpp_strerror(r)
+ bool more_entries;
+ uint32_t max_read = 1024;
+ std::string last_read = "";
+ do {
+ map<string, cls::rbd::TrashImageSpec> trash_entries;
+ int r = cls_client::trash_list(&io_ctx, last_read, max_read,
+ &trash_entries);
+ if (r < 0 && r != -ENOENT) {
+ lderr(cct) << "error listing rbd trash entries: " << cpp_strerror(r)
<< dendl;
- } else {
- r = 0;
+ return r;
+ } else if (r == -ENOENT) {
+ break;
}
- return r;
- }
- for (const auto &entry : trash_entries) {
- rbd_trash_image_source_t source =
- static_cast<rbd_trash_image_source_t>(entry.second.source);
- entries.push_back({entry.first, entry.second.name, source,
- entry.second.deletion_time.sec(),
- entry.second.deferment_end_time.sec()});
- }
+ if (trash_entries.empty()) {
+ break;
+ }
+
+ for (const auto &entry : trash_entries) {
+ rbd_trash_image_source_t source =
+ static_cast<rbd_trash_image_source_t>(entry.second.source);
+ entries.push_back({entry.first, entry.second.name, source,
+ entry.second.deletion_time.sec(),
+ entry.second.deferment_end_time.sec()});
+ }
+ last_read = trash_entries.rbegin()->first;
+ more_entries = (trash_entries.size() >= max_read);
+ } while (more_entries);
+
return 0;
}
string id2 = "123456780";
std::map<string, cls::rbd::TrashImageSpec> entries;
- ASSERT_EQ(-ENOENT, trash_list(&ioctx, &entries));
+ ASSERT_EQ(-ENOENT, trash_list(&ioctx, "", 1024, &entries));
utime_t now1 = ceph_clock_now();
utime_t now1_delay = now1;
ASSERT_EQ(0, trash_remove(&ioctx, id));
ASSERT_EQ(-ENOENT, trash_remove(&ioctx, id));
- ASSERT_EQ(0, trash_list(&ioctx, &entries));
+ ASSERT_EQ(0, trash_list(&ioctx, "", 1024, &entries));
ASSERT_TRUE(entries.empty());
ASSERT_EQ(0, trash_add(&ioctx, id, trash_spec2));
ASSERT_EQ(0, trash_add(&ioctx, id2, trash_spec));
- ASSERT_EQ(0, trash_list(&ioctx, &entries));
-
- for (auto& entry : entries) {
- if (entry.first == id) {
- ASSERT_EQ(entry.second.source, cls::rbd::TRASH_IMAGE_SOURCE_MIRRORING);
- ASSERT_EQ(entry.second.name, "name2");
- ASSERT_EQ(entry.second.deletion_time, now2);
- ASSERT_EQ(entry.second.deferment_end_time, now2_delay);
- } else if (entry.first == id2) {
- ASSERT_EQ(entry.second.source, cls::rbd::TRASH_IMAGE_SOURCE_USER);
- ASSERT_EQ(entry.second.name, "name");
- ASSERT_EQ(entry.second.deletion_time, now1);
- ASSERT_EQ(entry.second.deferment_end_time, now1_delay);
- }
- }
+ ASSERT_EQ(0, trash_list(&ioctx, "", 1, &entries));
+ ASSERT_TRUE(entries.find(id2) != entries.end());
+ ASSERT_EQ(cls::rbd::TRASH_IMAGE_SOURCE_USER, entries[id2].source);
+ ASSERT_EQ(std::string("name"), entries[id2].name);
+ ASSERT_EQ(now1, entries[id2].deletion_time);
+ ASSERT_EQ(now1_delay, entries[id2].deferment_end_time);
+
+ ASSERT_EQ(0, trash_list(&ioctx, id2, 1, &entries));
+ ASSERT_TRUE(entries.find(id) != entries.end());
+ ASSERT_EQ(cls::rbd::TRASH_IMAGE_SOURCE_MIRRORING, entries[id].source);
+ ASSERT_EQ(std::string("name2"), entries[id].name);
+ ASSERT_EQ(now2, entries[id].deletion_time);
+ ASSERT_EQ(now2_delay, entries[id].deferment_end_time);
+
+ ASSERT_EQ(0, trash_list(&ioctx, id, 1, &entries));
+ ASSERT_TRUE(entries.empty());
cls::rbd::TrashImageSpec spec_res1;
ASSERT_EQ(0, trash_get(&ioctx, id, &spec_res1));