]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
librados: seek during object iteration
authorSage Weil <sage@inktank.com>
Thu, 10 Oct 2013 18:51:16 +0000 (11:51 -0700)
committerSage Weil <sage@inktank.com>
Sat, 14 Dec 2013 00:35:56 +0000 (16:35 -0800)
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>
Signed-off-by: Greg Farnum <greg@inktank.com>
src/include/rados/librados.h
src/include/rados/librados.hpp
src/librados/IoCtxImpl.cc
src/librados/IoCtxImpl.h
src/librados/librados.cc
src/osdc/Objecter.cc
src/osdc/Objecter.h
src/test/librados/list.cc

index c6fe4784753a2b21365ab3ce1cd16373f8e0e7a0..d6c9ff17e601f895fc746e05c581ccba17025bd3 100644 (file)
@@ -709,6 +709,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
  *
index f1bb67f9d6bc1041cec1ebbcf89157dbbaef658a..388af64976249d1252551000e0993abcbdcd4756 100644 (file)
@@ -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;
@@ -625,7 +628,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;
 
     /**
index 0e1046d6bf5b7979ffe129b1453552816600d995..627bd3b2140339731080bf715e2458314e397fd7 100644 (file)
@@ -400,6 +400,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;
index 2d85f48be24cdefd07fbfd6e6e8cfc8541d69f8d..aa94aa83bba1981dca77e06590dea83b37ec9d3d 100644 (file)
@@ -111,6 +111,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);
index af5a467600e12e6ecf9faa106e60c0ec0cd4d475..c0bdebf8527ec794564ea7da2d498b9943fe13e1 100644 (file)
@@ -504,6 +504,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;
@@ -1174,6 +1181,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;
@@ -2625,6 +2642,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)
 {
index 75144304d29d2954a95472d016945715c7c116ea..9b8f27e7853de43d631c301fde8d28cee3858c55 100644 (file)
@@ -1769,8 +1769,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
index 80dd67aab48364515d4835da3d442a9f9aa72cb4..704e4127a4bc6a1e0a0ab682791bff0d8bd39c76 100644 (file)
@@ -1923,6 +1923,7 @@ private:
   }
 
   void list_objects(ListContext *p, Context *onfinish);
+  uint32_t list_objects_seek(ListContext *p, uint32_t pos);
 
   // -------------------------
   // pool ops
index ddce0b843531de825ec2496f464c5da78cb6e8d4..30e18b790c3ca6a0a51f99cd01c273817ed08fa1 100644 (file)
@@ -4,6 +4,7 @@
 #include "include/stringify.h"
 #include "test/librados/test.h"
 
+#include "include/types.h"
 #include "gtest/gtest.h"
 #include <errno.h>
 #include <string>
@@ -228,3 +229,82 @@ 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;
+  }
+  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()) {
+    ASSERT_EQ((uint32_t)p->first, it.seek(p->first));
+    std::cout << "have " << it->first << " expect one of " << p->second << std::endl;
+    ASSERT_TRUE(p->second.count(it->first));
+    ++p;
+  }
+
+  ioctx.close();
+  ASSERT_EQ(0, destroy_one_pool_pp(pool_name, cluster));
+}