summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSage Weil <sage@inktank.com>2013-10-10 11:51:16 -0700
committerSage Weil <sage@inktank.com>2013-10-10 11:51:38 -0700
commit562d7816ef3bab4bdd4a823184c8f5477b94b4d7 (patch)
treebef55f3d8625898acba3fa26308dc5b3b0dc6d29
parent67f80754bda81017c8d5828c88a81a55945bbe5b (diff)
downloadceph-wip-rados-list.tar.gz
librados: seek during object iterationwip-rados-list
Add ability to reset iterator to a specific hash position. For now, we just truncate this to the current PG. In the future, this may be more precise. Signed-off-by: Sage Weil <sage@inktank.com>
-rw-r--r--src/include/rados/librados.h9
-rw-r--r--src/include/rados/librados.hpp7
-rw-r--r--src/librados/IoCtxImpl.cc8
-rw-r--r--src/librados/IoCtxImpl.h1
-rw-r--r--src/librados/librados.cc25
-rw-r--r--src/osdc/Objecter.cc18
-rw-r--r--src/osdc/Objecter.h1
-rw-r--r--src/test/librados/list.cc87
8 files changed, 155 insertions, 1 deletions
diff --git a/src/include/rados/librados.h b/src/include/rados/librados.h
index 449aeebe41a..eaf43ab6339 100644
--- a/src/include/rados/librados.h
+++ b/src/include/rados/librados.h
@@ -693,6 +693,15 @@ int rados_objects_list_open(rados_ioctx_t io, rados_list_ctx_t *ctx);
uint32_t rados_objects_list_get_pg_hash_position(rados_list_ctx_t ctx);
/**
+ * Reposition object iterator to a different hash position
+ *
+ * @param ctx iterator marking where you are in the listing
+ * @param pos hash position to move to
+ * @returns actual (rounded) position we moved to
+ */
+uint32_t rados_objects_list_seek(rados_list_ctx_t ctx, uint32_t pos);
+
+/**
* Get the next object name and locator in the pool
*
* *entry and *key are valid until next call to rados_objects_list_*
diff --git a/src/include/rados/librados.hpp b/src/include/rados/librados.hpp
index 46cedd578c5..d788e5ecf61 100644
--- a/src/include/rados/librados.hpp
+++ b/src/include/rados/librados.hpp
@@ -75,6 +75,9 @@ namespace librados
/// get current hash position of the iterator, rounded to the current pg
uint32_t get_pg_hash_position() const;
+ /// move the iterator to a given hash position. this may (will!) be rounded to the nearest pg.
+ uint32_t seek(uint32_t pos);
+
private:
void get_next();
std::tr1::shared_ptr < ObjListCtx > ctx;
@@ -588,7 +591,11 @@ namespace librados
std::list<librados::locker_t> *lockers);
+ /// Start enumerating objects for a pool
ObjectIterator objects_begin();
+ /// Start enumerating objects for a pool starting from a hash position
+ ObjectIterator objects_begin(uint32_t start_hash_position);
+ /// Iterator indicating the end of a pool
const ObjectIterator& objects_end() const;
uint64_t get_last_version();
diff --git a/src/librados/IoCtxImpl.cc b/src/librados/IoCtxImpl.cc
index 6d35f6ba6f4..ae943f8bc92 100644
--- a/src/librados/IoCtxImpl.cc
+++ b/src/librados/IoCtxImpl.cc
@@ -388,6 +388,14 @@ int librados::IoCtxImpl::list(Objecter::ListContext *context, int max_entries)
return r;
}
+uint32_t librados::IoCtxImpl::list_seek(Objecter::ListContext *context,
+ uint32_t pos)
+{
+ Mutex::Locker l(*lock);
+ context->list.clear();
+ return objecter->list_objects_seek(context, pos);
+}
+
int librados::IoCtxImpl::create(const object_t& oid, bool exclusive)
{
::ObjectOperation op;
diff --git a/src/librados/IoCtxImpl.h b/src/librados/IoCtxImpl.h
index ccecd4e8184..6137ba91257 100644
--- a/src/librados/IoCtxImpl.h
+++ b/src/librados/IoCtxImpl.h
@@ -108,6 +108,7 @@ struct librados::IoCtxImpl {
// io
int list(Objecter::ListContext *context, int max_entries);
+ uint32_t list_seek(Objecter::ListContext *context, uint32_t pos);
int create(const object_t& oid, bool exclusive);
int create(const object_t& oid, bool exclusive, const std::string& category);
int write(const object_t& oid, bufferlist& bl, size_t len, uint64_t off);
diff --git a/src/librados/librados.cc b/src/librados/librados.cc
index a916abcff26..f4a2a0c2786 100644
--- a/src/librados/librados.cc
+++ b/src/librados/librados.cc
@@ -488,6 +488,13 @@ librados::ObjectIterator librados::ObjectIterator::operator++(int)
return ret;
}
+uint32_t librados::ObjectIterator::seek(uint32_t pos)
+{
+ uint32_t r = rados_objects_list_seek(ctx.get(), pos);
+ get_next();
+ return r;
+}
+
void librados::ObjectIterator::get_next()
{
const char *entry, *key;
@@ -1136,6 +1143,16 @@ librados::ObjectIterator librados::IoCtx::objects_begin()
return iter;
}
+librados::ObjectIterator librados::IoCtx::objects_begin(uint32_t pos)
+{
+ rados_list_ctx_t listh;
+ rados_objects_list_open(io_ctx_impl, &listh);
+ ObjectIterator iter((ObjListCtx*)listh);
+ iter.seek(pos);
+ iter.get_next();
+ return iter;
+}
+
const librados::ObjectIterator& librados::IoCtx::objects_end() const
{
return ObjectIterator::__EndObjectIterator;
@@ -2534,6 +2551,14 @@ extern "C" void rados_objects_list_close(rados_list_ctx_t h)
delete lh;
}
+extern "C" uint32_t rados_objects_list_seek(rados_list_ctx_t listctx,
+ uint32_t pos)
+{
+ librados::ObjListCtx *lh = (librados::ObjListCtx *)listctx;
+ uint32_t r = lh->ctx->list_seek(lh->lc, pos);
+ return r;
+}
+
extern "C" uint32_t rados_objects_list_get_pg_hash_position(
rados_list_ctx_t listctx)
{
diff --git a/src/osdc/Objecter.cc b/src/osdc/Objecter.cc
index f767641a0f7..89f99f1a927 100644
--- a/src/osdc/Objecter.cc
+++ b/src/osdc/Objecter.cc
@@ -1714,8 +1714,24 @@ void Objecter::handle_osd_op_reply(MOSDOpReply *m)
}
-void Objecter::list_objects(ListContext *list_context, Context *onfinish) {
+uint32_t Objecter::list_objects_seek(ListContext *list_context,
+ uint32_t pos)
+{
+ assert(client_lock.is_locked());
+ pg_t actual = osdmap->raw_pg_to_pg(pg_t(pos, list_context->pool_id));
+ ldout(cct, 10) << "list_objects_seek " << list_context
+ << " pos " << pos << " -> " << actual << dendl;
+ list_context->current_pg = actual.ps();
+ list_context->cookie = collection_list_handle_t();
+ list_context->at_end_of_pg = false;
+ list_context->at_end_of_pool = false;
+ list_context->current_pg_epoch = 0;
+ return list_context->current_pg;
+}
+void Objecter::list_objects(ListContext *list_context, Context *onfinish)
+{
+ assert(client_lock.is_locked());
ldout(cct, 10) << "list_objects" << dendl;
ldout(cct, 20) << " pool_id " << list_context->pool_id
<< " pool_snap_seq " << list_context->pool_snap_seq
diff --git a/src/osdc/Objecter.h b/src/osdc/Objecter.h
index 4e6fa77e69b..20c12d8e48d 100644
--- a/src/osdc/Objecter.h
+++ b/src/osdc/Objecter.h
@@ -1812,6 +1812,7 @@ private:
}
void list_objects(ListContext *p, Context *onfinish);
+ uint32_t list_objects_seek(ListContext *p, uint32_t pos);
// -------------------------
// pool ops
diff --git a/src/test/librados/list.cc b/src/test/librados/list.cc
index fca0ad40395..d2aeec25e96 100644
--- a/src/test/librados/list.cc
+++ b/src/test/librados/list.cc
@@ -3,6 +3,7 @@
#include "include/stringify.h"
#include "test/librados/test.h"
+#include "include/types.h"
#include "gtest/gtest.h"
#include <errno.h>
#include <string>
@@ -214,3 +215,89 @@ TEST(LibRadosList, ListObjectsManyPP) {
ASSERT_EQ(0, destroy_one_pool_pp(pool_name, cluster));
}
+
+
+TEST(LibRadosList, ListObjectsStart) {
+ rados_t cluster;
+ rados_ioctx_t ioctx;
+ std::string pool_name = get_temp_pool_name();
+ ASSERT_EQ("", create_one_pool(pool_name, &cluster));
+ rados_ioctx_create(cluster, pool_name.c_str(), &ioctx);
+
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+
+ for (int i=0; i<16; ++i) {
+ string n = stringify(i);
+ ASSERT_EQ((int)sizeof(buf), rados_write(ioctx, n.c_str(), buf, sizeof(buf), 0));
+ }
+
+ rados_list_ctx_t ctx;
+ ASSERT_EQ(0, rados_objects_list_open(ioctx, &ctx));
+ std::map<int, std::set<std::string> > pg_to_obj;
+ const char *entry;
+ while (rados_objects_list_next(ctx, &entry, NULL) == 0) {
+ uint32_t pos = rados_objects_list_get_pg_hash_position(ctx);
+ std::cout << entry << " " << pos << std::endl;
+ pg_to_obj[pos].insert(entry);
+ }
+ rados_objects_list_close(ctx);
+
+ std::map<int, std::set<std::string> >::reverse_iterator p =
+ pg_to_obj.rbegin();
+ ASSERT_EQ(0, rados_objects_list_open(ioctx, &ctx));
+ while (p != pg_to_obj.rend()) {
+ ASSERT_EQ((uint32_t)p->first, rados_objects_list_seek(ctx, p->first));
+ ASSERT_EQ(0, rados_objects_list_next(ctx, &entry, NULL));
+ std::cout << "have " << entry << " expect one of " << p->second << std::endl;
+ ASSERT_TRUE(p->second.count(entry));
+
+ ++p;
+ if (p == pg_to_obj.rend())
+ break;
+ }
+ rados_objects_list_close(ctx);
+ rados_ioctx_destroy(ioctx);
+ ASSERT_EQ(0, destroy_one_pool(pool_name, &cluster));
+}
+
+TEST(LibRadosList, ListObjectsStartPP) {
+ std::string pool_name = get_temp_pool_name();
+ Rados cluster;
+ ASSERT_EQ("", create_one_pool_pp(pool_name, cluster));
+ IoCtx ioctx;
+ cluster.ioctx_create(pool_name.c_str(), ioctx);
+
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl;
+ bl.append(buf, sizeof(buf));
+
+ for (int i=0; i<16; ++i) {
+ ASSERT_EQ((int)sizeof(buf), ioctx.write(stringify(i), bl, bl.length(), 0));
+ }
+
+ librados::ObjectIterator it = ioctx.objects_begin();
+ std::map<int, std::set<std::string> > pg_to_obj;
+ for (; it != ioctx.objects_end(); ++it) {
+ std::cout << it->first << " " << it.get_pg_hash_position() << std::endl;
+ pg_to_obj[it.get_pg_hash_position()].insert(it->first);
+ }
+
+ std::map<int, std::set<std::string> >::reverse_iterator p =
+ pg_to_obj.rbegin();
+ it = ioctx.objects_begin(p->first);
+ while (p != pg_to_obj.rend()) {
+ std::cout << "have " << it->first << " expect one of " << p->second << std::endl;
+ ASSERT_TRUE(p->second.count(it->first));
+
+ ++p;
+ if (p == pg_to_obj.rend())
+ break;
+ ASSERT_EQ((uint32_t)p->first, it.seek(p->first));
+ }
+
+ ioctx.close();
+ ASSERT_EQ(0, destroy_one_pool_pp(pool_name, cluster));
+}
+