]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
src/test: RadosModel (redirected I/O test, Set/Unset Redirect)
authormyoungwon oh <omwmw@sk.com>
Sat, 6 May 2017 04:21:04 +0000 (13:21 +0900)
committermyoungwon oh <omwmw@sk.com>
Tue, 16 May 2017 20:44:20 +0000 (05:44 +0900)
Signed-off-by: Myoungwon Oh omwmw@sk.com
src/test/osd/Object.h
src/test/osd/RadosModel.h
src/test/osd/TestRados.cc

index 85a75a56ca9d70980cbf99b4d7414620ce6d38c2..09a59a9ceb5cc8ac32b016909c5e65f09ffcfe13 100644 (file)
@@ -506,6 +506,7 @@ public:
   bool dirty;
 
   uint64_t version;
+  std::string redirect_target;
 private:
   std::list<std::pair<ceph::shared_ptr<ContentsGenerator>, ContDesc> > layers;
 };
index bbec3b0cdec5e21195c11b3648faa3be903599cd..ff44fee01e97d44a6152a18b184e245e9315627f 100644 (file)
@@ -64,7 +64,9 @@ enum TestOpType {
   TEST_OP_CACHE_TRY_FLUSH,
   TEST_OP_CACHE_EVICT,
   TEST_OP_APPEND,
-  TEST_OP_APPEND_EXCL
+  TEST_OP_APPEND_EXCL,
+  TEST_OP_SET_REDIRECT,
+  TEST_OP_UNSET_REDIRECT
 };
 
 class TestWatchContext : public librados::WatchCtx2 {
@@ -166,6 +168,8 @@ public:
   set<string> oid_not_in_use;
   set<string> oid_flushing;
   set<string> oid_not_flushing;
+  set<string> oid_redirect_not_in_use;
+  set<string> oid_redirect_in_use;
   SharedPtrRegistry<int, int> snaps_in_use;
   int current_snap;
   string pool_name;
@@ -190,6 +194,7 @@ public:
   bool pool_snaps;
   bool write_fadvise_dontneed;
   int snapname_num;
+  map<string,string > redirect_objs;
 
   RadosTestContext(const string &pool_name, 
                   int max_in_flight,
@@ -477,6 +482,11 @@ public:
     return false;
   }
 
+  void update_object_redirect_target(const string &oid, const string &target)
+  {
+    redirect_objs[oid] = target;
+  }
+
   bool object_existed_at(const string &oid, int snap = -1) const
   {
     ObjectDesc contents;
@@ -1948,6 +1958,224 @@ public:
   }
 };
 
+class SetRedirectOp : public TestOp {
+public:
+  string oid, oid_tgt, tgt_pool_name;
+  ObjectDesc src_value, tgt_value;
+  librados::ObjectWriteOperation op;
+  librados::ObjectReadOperation rd_op;
+  librados::AioCompletion *comp;
+  ceph::shared_ptr<int> in_use;
+  int done;
+  int r;
+  SetRedirectOp(int n,
+            RadosTestContext *context,
+            const string &oid,
+            const string &oid_tgt,
+            const string &tgt_pool_name,
+            TestOpStat *stat = 0)
+    : TestOp(n, context, stat),
+      oid(oid), oid_tgt(oid_tgt), tgt_pool_name(tgt_pool_name),
+      comp(NULL), done(0), 
+      r(0)
+  {}
+
+  void _begin() override
+  {
+    Mutex::Locker l(context->state_lock);
+    context->oid_in_use.insert(oid);
+    context->oid_not_in_use.erase(oid);
+    context->oid_redirect_in_use.insert(oid_tgt);
+    context->oid_redirect_not_in_use.erase(oid_tgt);
+
+    context->find_object(oid, &src_value); 
+    if(!context->redirect_objs[oid].empty()) {
+      /* update target's user_version */
+      rd_op.stat(NULL, NULL, NULL);
+      comp = context->rados.aio_create_completion();
+      context->io_ctx.aio_operate(context->prefix+oid_tgt, comp, &rd_op,
+                           librados::OPERATION_ORDER_READS_WRITES,
+                           NULL);
+      comp->wait_for_safe();
+      context->update_object_version(oid_tgt, comp->get_version64());
+      comp->release();
+
+      /* unset redirect target */
+      comp = context->rados.aio_create_completion();
+      bool present = !src_value.deleted();
+      context->remove_object(oid);
+      op.remove();
+      context->io_ctx.aio_operate(context->prefix+oid, comp, &op,
+                                 librados::OPERATION_ORDER_READS_WRITES |
+                                 librados::OPERATION_IGNORE_REDIRECT);
+      comp->wait_for_safe();
+      if ((r = comp->get_return_value())) {
+       if (!(r == -ENOENT && !present)) {
+         cerr << "r is " << r << " while deleting " << oid << " and present is " << present << std::endl;
+         ceph_abort();
+       }
+      }
+      comp->release();
+
+      context->oid_redirect_not_in_use.insert(context->redirect_objs[oid]);
+      context->oid_redirect_in_use.erase(context->redirect_objs[oid]);
+
+      /* copy_from oid_tgt --> oid */
+      comp = context->rados.aio_create_completion();
+      context->find_object(oid_tgt, &tgt_value);
+      string src = context->prefix+oid_tgt;
+      op.copy_from(src.c_str(), context->io_ctx, tgt_value.version);
+      context->io_ctx.aio_operate(context->prefix+oid, comp, &op,
+                                 librados::OPERATION_ORDER_READS_WRITES);
+      comp->wait_for_safe();
+      if ((r = comp->get_return_value())) {
+       cerr << "Error: oid " << oid << " copy_from " << oid_tgt << " returned error code "
+            << r << std::endl;
+       ceph_abort();
+      }
+      context->update_object_full(oid, tgt_value);
+      context->update_object_version(oid, comp->get_version64());
+      comp->release();
+    }
+
+    comp = context->rados.aio_create_completion();
+    rd_op.stat(NULL, NULL, NULL);
+    context->io_ctx.aio_operate(context->prefix+oid, comp, &rd_op,
+                         librados::OPERATION_ORDER_READS_WRITES |
+                         librados::OPERATION_IGNORE_REDIRECT,
+                         NULL);
+    comp->wait_for_safe();
+    if ((r = comp->get_return_value()) && !src_value.deleted()) {
+      cerr << "Error: oid " << oid << " stat returned error code "
+          << r << std::endl;
+      ceph_abort();
+    }
+    context->update_object_version(oid, comp->get_version64());
+    comp->release();
+
+    context->find_object(oid, &src_value); 
+    context->find_object(oid_tgt, &tgt_value);
+
+    if (!src_value.deleted() && !tgt_value.deleted())
+      context->update_object_full(oid, tgt_value);
+
+    if (src_value.version != 0 && !src_value.deleted())
+      op.assert_version(src_value.version);
+    op.set_redirect(context->prefix+oid_tgt, context->io_ctx, tgt_value.version);
+
+    pair<TestOp*, TestOp::CallbackInfo*> *cb_arg =
+      new pair<TestOp*, TestOp::CallbackInfo*>(this,
+                                              new TestOp::CallbackInfo(0));
+    comp = context->rados.aio_create_completion((void*) cb_arg, NULL,
+                                               &write_callback);
+    context->io_ctx.aio_operate(context->prefix+oid, comp, &op,
+                               librados::OPERATION_ORDER_READS_WRITES);
+  }
+
+  void _finish(CallbackInfo *info) override
+  {
+    Mutex::Locker l(context->state_lock);
+
+    if (info->id == 0) {
+      assert(comp->is_complete());
+      cout << num << ":  finishing set_redirect to oid " << oid << std::endl;
+      if ((r = comp->get_return_value())) {
+       if (r == -ENOENT && src_value.deleted()) {
+         cout << num << ":  got expected ENOENT (src dne)" << std::endl;
+       } else {
+         cerr << "Error: oid " << oid << " set_redirect " << oid_tgt << " returned error code "
+              << r << std::endl;
+         ceph_abort();
+       }
+      } else {
+       context->update_object_redirect_target(oid, oid_tgt);
+       context->update_object_version(oid, comp->get_version64());
+      }
+    }
+
+    if (++done == 1) {
+      context->oid_in_use.erase(oid);
+      context->oid_not_in_use.insert(oid);
+      context->kick();
+    }
+  }
+
+  bool finished() override
+  {
+    return done == 1;
+  }
+
+  string getType() override
+  {
+    return "SetRedirectOp";
+  }
+};
+
+class UnsetRedirectOp : public TestOp {
+public:
+  string oid;
+  librados::ObjectWriteOperation op;
+  librados::AioCompletion *completion;
+  librados::AioCompletion *comp;
+
+  UnsetRedirectOp(int n,
+          RadosTestContext *context,
+          const string &oid,
+          TestOpStat *stat = 0)
+    : TestOp(n, context, stat), oid(oid)
+  {}
+
+  void _begin() override
+  {
+    context->state_lock.Lock();
+    if (context->get_watch_context(oid)) {
+      context->kick();
+      context->state_lock.Unlock();
+      return;
+    }
+
+    ObjectDesc contents;
+    context->find_object(oid, &contents);
+    bool present = !contents.deleted();
+
+    context->oid_in_use.insert(oid);
+    context->oid_not_in_use.erase(oid);
+    context->seq_num++;
+
+    context->remove_object(oid);
+
+    context->state_lock.Unlock();
+
+    comp = context->rados.aio_create_completion();
+    op.remove();
+    context->io_ctx.aio_operate(context->prefix+oid, comp, &op,
+                               librados::OPERATION_ORDER_READS_WRITES |
+                               librados::OPERATION_IGNORE_REDIRECT);
+    comp->wait_for_safe();
+    int r = comp->get_return_value();
+    if (r && !(r == -ENOENT && !present)) {
+      cerr << "r is " << r << " while deleting " << oid << " and present is " << present << std::endl;
+      ceph_abort();
+    }
+
+    context->state_lock.Lock();
+    context->oid_in_use.erase(oid);
+    context->oid_not_in_use.insert(oid);
+    if(!context->redirect_objs[oid].empty()) {
+      context->oid_redirect_not_in_use.insert(context->redirect_objs[oid]);
+      context->oid_redirect_in_use.erase(context->redirect_objs[oid]);
+      context->update_object_redirect_target(oid, string());
+    }
+    context->kick();
+    context->state_lock.Unlock();
+  }
+
+  string getType() override
+  {
+    return "UnsetRedirectOp";
+  }
+};
+
 class HitSetListOp : public TestOp {
   librados::AioCompletion *comp1, *comp2;
   uint32_t hash;
index 4a1bf8ef374f798932e682b843d1889085459138..0fb2e776cb4b2adddc7c502cca037ba7ec9e9270 100644 (file)
@@ -29,12 +29,14 @@ public:
                        TestOpStat *stats,
                        int max_seconds,
                        bool ec_pool,
-                       bool balance_reads) :
+                       bool balance_reads,
+                       bool set_redirect) :
     m_nextop(NULL), m_op(0), m_ops(ops), m_seconds(max_seconds),
     m_objects(objects), m_stats(stats),
     m_total_weight(0),
     m_ec_pool(ec_pool),
-    m_balance_reads(balance_reads)
+    m_balance_reads(balance_reads),
+    m_set_redirect(set_redirect)
   {
     m_start = time(0);
     for (map<TestOpType, unsigned int>::const_iterator it = op_weights.begin();
@@ -44,6 +46,12 @@ public:
       m_weight_sums.insert(pair<TestOpType, unsigned int>(it->first,
                                                          m_total_weight));
     }
+    if (m_set_redirect) {
+      /* create redirect objects + set-redirect*/
+      m_redirect_objects = objects*2; // for copy_from + set-redirect test
+      m_initial_redirected_objects = objects;
+      m_ops = ops+m_redirect_objects+m_initial_redirected_objects;
+    }
   }
 
   TestOp *next(RadosTestContext &context) override
@@ -68,6 +76,66 @@ public:
     } else if (m_op >= m_ops) {
       return NULL;
     }
+    
+    if (m_set_redirect) {
+      /*
+       * set-redirect test
+       * 1. create objects (copy from)
+       * 2. set-redirect
+       */
+      int create_objects_end = m_objects + m_redirect_objects;
+      int set_redirect_end = create_objects_end + m_initial_redirected_objects; 
+
+      if (m_op <= create_objects_end) {
+       stringstream oid;
+       int _oid = m_op;
+       oid << _oid;
+       if ((_oid) % 2) {
+         oid << " " << string(300, 'o');
+       }
+       stringstream oid2;
+       int _oid2 = _oid - m_objects;
+       oid2 << _oid2;
+       if ((_oid2) % 2) {
+         oid2 << " " << string(300, 'o');
+       }
+       cout << m_op << ": " << "(create redirect oid) copy_from oid " << oid.str() 
+             << " from oid " << oid2.str() << std::endl;
+       return new CopyFromOp(m_op, &context, oid.str(), oid2.str(), m_stats);
+      } else if (m_op <= set_redirect_end) {
+       stringstream oid;
+       int _oid = m_op-create_objects_end;
+       oid << _oid;
+       if ((_oid) % 2) {
+         oid << " " << string(300, 'o');
+       }
+       stringstream oid2;
+       int _oid2 = _oid + m_objects;
+       oid2 << _oid2;
+       if ((_oid2) % 2) {
+         oid2 << " " << string(300, 'o');
+       }
+       cout << m_op << ": " << "set_redirect oid " << oid.str() << " target oid " 
+             << oid2.str() << std::endl;
+       return new SetRedirectOp(m_op, &context, oid.str(), oid2.str(), context.pool_name);
+      } 
+
+      if (!context.oid_redirect_not_in_use.size() && m_op == set_redirect_end+1) {
+       for (int t_op = m_objects+1; t_op <= create_objects_end; t_op++) {
+         stringstream oid;
+         oid << t_op;
+         if (t_op % 2) {
+           oid << " " << string(300, 'o');
+         }
+         context.oid_not_flushing.erase(oid.str());
+         context.oid_not_in_use.erase(oid.str());
+         context.oid_in_use.erase(oid.str());
+         if (t_op > m_objects + m_initial_redirected_objects) {
+           context.oid_redirect_not_in_use.insert(oid.str());
+         }
+       }
+      }
+    }
 
     if (m_nextop) {
       retval = m_nextop;
@@ -234,6 +302,17 @@ private:
           << context.current_snap << std::endl;
       return new WriteOp(m_op, &context, oid, true, true, m_stats);
 
+    case TEST_OP_SET_REDIRECT:
+      oid = *(rand_choose(context.oid_not_in_use));
+      oid2 = *(rand_choose(context.oid_redirect_not_in_use));
+      cout << m_op << ": " << "set_redirect oid " << oid << " target oid " << oid2 << std::endl;
+      return new SetRedirectOp(m_op, &context, oid, oid2, context.pool_name, m_stats);
+
+    case TEST_OP_UNSET_REDIRECT:
+      oid = *(rand_choose(context.oid_not_in_use));
+      cout << m_op << ": " << "unset_redirect oid " << oid << std::endl;
+      return new UnsetRedirectOp(m_op, &context, oid, m_stats);
+
     default:
       cerr << m_op << ": Invalid op type " << type << std::endl;
       ceph_abort();
@@ -252,6 +331,9 @@ private:
   unsigned int m_total_weight;
   bool m_ec_pool;
   bool m_balance_reads;
+  bool m_set_redirect;
+  int m_redirect_objects;
+  int m_initial_redirected_objects; 
 };
 
 int main(int argc, char **argv)
@@ -290,6 +372,8 @@ int main(int argc, char **argv)
     { TEST_OP_CACHE_EVICT, "cache_evict", true },
     { TEST_OP_APPEND, "append", true },
     { TEST_OP_APPEND_EXCL, "append_excl", true },
+    { TEST_OP_SET_REDIRECT, "set_redirect", true },
+    { TEST_OP_UNSET_REDIRECT, "unset_redirect", true },
     { TEST_OP_READ /* grr */, NULL },
   };
 
@@ -299,6 +383,7 @@ int main(int argc, char **argv)
   bool no_omap = false;
   bool no_sparse = false;
   bool balance_reads = false;
+  bool set_redirect = false;
 
   for (int i = 1; i < argc; ++i) {
     if (strcmp(argv[i], "--max-ops") == 0)
@@ -369,6 +454,8 @@ int main(int argc, char **argv)
        cout << "adding op weight " << op_types[j].name << " -> " << weight << std::endl;
        op_weights.insert(pair<TestOpType, unsigned int>(op_types[j].op, weight));
       }
+    } else if (strcmp(argv[i], "--set_redirect") == 0) {
+      set_redirect = true;
     } else {
       cerr << "unknown arg " << argv[i] << std::endl;
       //usage();
@@ -431,7 +518,7 @@ int main(int argc, char **argv)
   WeightedTestGenerator gen = WeightedTestGenerator(
     ops, objects,
     op_weights, &stats, max_seconds,
-    ec_pool, balance_reads);
+    ec_pool, balance_reads, set_redirect);
   int r = context.init();
   if (r < 0) {
     cerr << "Error initializing rados test context: "