]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
osd: add ISDIRTY, UNDIRTY rados operations 675/head
authorSage Weil <sage@inktank.com>
Wed, 2 Oct 2013 00:04:44 +0000 (17:04 -0700)
committerSage Weil <sage@inktank.com>
Wed, 2 Oct 2013 00:04:44 +0000 (17:04 -0700)
ISDIRTY will query whether the dirty flag is set on an object.  UNDIRTY
will explicitly clear it.  Note that a user doing so will likely run amok
with the caching code.

Signed-off-by: Sage Weil <sage@inktank.com>
src/common/ceph_strings.cc
src/include/rados.h
src/include/rados/librados.hpp
src/librados/librados.cc
src/osd/ReplicatedPG.cc
src/osd/ReplicatedPG.h
src/osd/osd_types.cc
src/osdc/Objecter.h
src/test/librados/misc.cc

index cd08083967aa4e5b2d0ca25213fd1f853660e7bc..47648ce19b33c600aabbcaddbcc428ac5302af2d 100644 (file)
@@ -50,6 +50,8 @@ const char *ceph_osd_op_name(int op)
 
        case CEPH_OSD_OP_COPY_GET: return "copy-get";
        case CEPH_OSD_OP_COPY_FROM: return "copy-from";
+       case CEPH_OSD_OP_UNDIRTY: return "undirty";
+       case CEPH_OSD_OP_ISDIRTY: return "isdirty";
 
        case CEPH_OSD_OP_CLONERANGE: return "clonerange";
        case CEPH_OSD_OP_ASSERT_SRC_VERSION: return "assert-src-version";
index 178c171c445ccdf3c5735b0b655dc51a01037c3b..e7a32b5afefe7bc39eed49ecee80caadba897efa 100644 (file)
@@ -219,6 +219,8 @@ enum {
 
        CEPH_OSD_OP_COPY_FROM = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 26,
        CEPH_OSD_OP_COPY_GET = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_DATA | 27,
+       CEPH_OSD_OP_UNDIRTY   = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 28,
+       CEPH_OSD_OP_ISDIRTY   = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_DATA | 29,
 
        /** multi **/
        CEPH_OSD_OP_CLONERANGE = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_MULTI | 1,
index 358142c8cb4c2654bda0a84fd81f86cfd6aa1373..3f6d025ff419bca9d210aa37e2a7b0dade7e5564 100644 (file)
@@ -283,6 +283,13 @@ namespace librados
      */
     void copy_from(const std::string& src, const IoCtx& src_ioctx, uint64_t src_version);
 
+    /**
+     * undirty an object
+     *
+     * Clear an objects dirty flag
+     */
+    void undirty();
+
     friend class IoCtx;
   };
 
@@ -401,6 +408,14 @@ namespace librados
      */
     void list_snaps(snap_set_t *out_snaps, int *prval);
 
+    /**
+     * query dirty state of an object
+     *
+     * @param out_dirty [out] pointer to resulting bool
+     * @param prval [out] place error code in prval upon completion
+     */
+    void is_dirty(bool *isdirty, int *prval);
+
   };
 
   /* IoCtx : This is a context in which we can perform I/O.
index 63092d1093d99f60e2e1e5ea6768c9b2455be139..217a0a7bfb2651656db9f66969b4cc67d97faad8 100644 (file)
@@ -269,6 +269,14 @@ void librados::ObjectReadOperation::list_snaps(
   o->list_snaps(out_snaps, prval);
 }
 
+void librados::ObjectReadOperation::is_dirty(bool *is_dirty, int *prval)
+{
+  ::ObjectOperation *o = (::ObjectOperation *)impl;
+  o->is_dirty(is_dirty, prval);
+}
+
+
+
 int librados::IoCtx::omap_get_vals(const std::string& oid,
                                    const std::string& start_after,
                                    const std::string& filter_prefix,
@@ -390,6 +398,12 @@ void librados::ObjectWriteOperation::copy_from(const std::string& src,
   o->copy_from(object_t(src), src_ioctx.io_ctx_impl->snap_seq, src_ioctx.io_ctx_impl->oloc, src_version);
 }
 
+void librados::ObjectWriteOperation::undirty()
+{
+  ::ObjectOperation *o = (::ObjectOperation *)impl;
+  o->undirty();
+}
+
 void librados::ObjectWriteOperation::tmap_put(const bufferlist &bl)
 {
   ::ObjectOperation *o = (::ObjectOperation *)impl;
index 20d589e0a2ae66eaa8e4bfacf72e464b2f17fde0..004b5193e4b02aae818cc5a250abce33d873e42a 100644 (file)
@@ -2634,6 +2634,25 @@ int ReplicatedPG::do_osd_ops(OpContext *ctx, vector<OSDOp>& ops)
       }
       break;
 
+    case CEPH_OSD_OP_ISDIRTY:
+      ++ctx->num_read;
+      {
+       bool is_dirty = obs.oi.is_dirty();
+       ::encode(is_dirty, osd_op.outdata);
+       ctx->delta_stats.num_rd++;
+       result = 0;
+      }
+      break;
+
+    case CEPH_OSD_OP_UNDIRTY:
+      ++ctx->num_write;
+      {
+       ctx->undirty = true;  // see make_writeable()
+       ctx->modify = true;
+       ctx->delta_stats.num_wr++;
+      }
+      break;
+
     case CEPH_OSD_OP_GETXATTR:
       ++ctx->num_read;
       {
@@ -2749,8 +2768,8 @@ int ReplicatedPG::do_osd_ops(OpContext *ctx, vector<OSDOp>& ops)
          result = -ERANGE;
        else if (ver > oi.user_version)
          result = -EOVERFLOW;
-       break;
       }
+      break;
 
     case CEPH_OSD_OP_LIST_WATCHERS:
       ++ctx->num_read;
@@ -3058,7 +3077,7 @@ int ReplicatedPG::do_osd_ops(OpContext *ctx, vector<OSDOp>& ops)
        }
       }
       break;
-      
+
     case CEPH_OSD_OP_TRIMTRUNC:
       op.extent.offset = op.extent.truncate_size;
       // falling through
@@ -3988,7 +4007,13 @@ void ReplicatedPG::make_writeable(OpContext *ctx)
           << "  snapc=" << snapc << dendl;;
   
   // we will mark the object dirty
-  ctx->new_obs.oi.set_flag(object_info_t::FLAG_DIRTY);
+  if (ctx->undirty) {
+    dout(20) << " clearing DIRTY flag" << dendl;
+    ctx->new_obs.oi.clear_flag(object_info_t::FLAG_DIRTY);
+  } else {
+    dout(20) << " setting DIRTY flag" << dendl;
+    ctx->new_obs.oi.set_flag(object_info_t::FLAG_DIRTY);
+  }
 
   // use newer snapc?
   if (ctx->new_snapset.seq > snapc.seq) {
index abee57ffe7d657ccaf7dcfc0dd175d8272d10af1..4b91a2135dc266e484d30d86cb5620a88c27b1c2 100644 (file)
@@ -254,6 +254,7 @@ public:
 
     bool modify;          // (force) modification (even if op_t is empty)
     bool user_modify;     // user-visible modification
+    bool undirty;         // user explicitly un-dirtying this object
 
     // side effects
     list<watch_info_t> watch_connects;
@@ -308,7 +309,7 @@ public:
              ReplicatedPG *_pg) :
       op(_op), reqid(_reqid), ops(_ops), obs(_obs), snapset(0),
       new_obs(_obs->oi, _obs->exists),
-      modify(false), user_modify(false),
+      modify(false), user_modify(false), undirty(false),
       bytes_written(0), bytes_read(0), user_at_version(0),
       current_osd_subop_num(0),
       data_off(0), reply(NULL), pg(_pg),
index 4ccad5eebb970e672e634c60e4ca8e3cbde93915..27f7b171677a220ae53d5b6e899e67729b5595d3 100644 (file)
@@ -3523,6 +3523,8 @@ ostream& operator<<(ostream& out, const OSDOp& op)
     case CEPH_OSD_OP_DELETE:
     case CEPH_OSD_OP_LIST_WATCHERS:
     case CEPH_OSD_OP_LIST_SNAPS:
+    case CEPH_OSD_OP_UNDIRTY:
+    case CEPH_OSD_OP_ISDIRTY:
       break;
     case CEPH_OSD_OP_ASSERT_VER:
       out << " v" << op.op.assert_ver.ver;
index 7e8cd60c1e94252f227dcec34dec6a54503957eb..1196633276d4374491548444f5676ca43bfe8f33 100644 (file)
@@ -644,6 +644,43 @@ struct ObjectOperation {
     out_handler[p] = h;
   }
 
+  void undirty() {
+    add_op(CEPH_OSD_OP_UNDIRTY);
+  }
+
+  struct C_ObjectOperation_isdirty : public Context {
+    bufferlist bl;
+    bool *pisdirty;
+    int *prval;
+    C_ObjectOperation_isdirty(bool *p, int *r)
+      : pisdirty(p), prval(r) {}
+    void finish(int r) {
+      if (r < 0)
+       return;
+      try {
+       bufferlist::iterator p = bl.begin();
+       bool isdirty;
+       ::decode(isdirty, p);
+       if (pisdirty)
+         *pisdirty = isdirty;
+      } catch (buffer::error& e) {
+       r = -EIO;
+      }
+      if (prval)
+       *prval = r;
+    }
+  };
+
+  void is_dirty(bool *pisdirty, int *prval) {
+    add_op(CEPH_OSD_OP_ISDIRTY);
+    unsigned p = ops.size() - 1;
+    out_rval[p] = prval;
+    C_ObjectOperation_isdirty *h =
+      new C_ObjectOperation_isdirty(pisdirty, prval);
+    out_bl[p] = &h->bl;
+    out_handler[p] = h;
+  }
+
   void omap_get_header(bufferlist *bl, int *prval) {
     add_op(CEPH_OSD_OP_OMAPGETHEADER);
     unsigned p = ops.size() - 1;
index 20847e7b8b915c4bb0386df7f28d6b7e552b7209..9abac9c412a6fe2f533f9d7871de1ffcfe76923c 100644 (file)
@@ -647,6 +647,60 @@ TEST(LibRadosMisc, CopyPP) {
   ASSERT_EQ(0, destroy_one_pool_pp(pool_name, cluster));
 }
 
+TEST(LibRadosMisc, Dirty) {
+  Rados cluster;
+  std::string pool_name = get_temp_pool_name();
+  ASSERT_EQ("", create_one_pool_pp(pool_name, cluster));
+  IoCtx ioctx;
+  ASSERT_EQ(0, cluster.ioctx_create(pool_name.c_str(), ioctx));
+
+  {
+    ObjectWriteOperation op;
+    op.create(true);
+    ASSERT_EQ(0, ioctx.operate("foo", &op));
+  }
+  {
+    bool dirty = false;
+    int r = -1;
+    ObjectReadOperation op;
+    op.is_dirty(&dirty, &r);
+    ASSERT_EQ(0, ioctx.operate("foo", &op, NULL));
+    ASSERT_TRUE(dirty);
+    ASSERT_EQ(0, r);
+  }
+  {
+    ObjectWriteOperation op;
+    op.undirty();
+    ASSERT_EQ(0, ioctx.operate("foo", &op));
+  }
+  {
+    bool dirty = false;
+    int r = -1;
+    ObjectReadOperation op;
+    op.is_dirty(&dirty, &r);
+    ASSERT_EQ(0, ioctx.operate("foo", &op, NULL));
+    ASSERT_FALSE(dirty);
+    ASSERT_EQ(0, r);
+  }
+  {
+    ObjectWriteOperation op;
+    op.truncate(0);  // still a write even tho it is a no-op
+    ASSERT_EQ(0, ioctx.operate("foo", &op));
+  }
+  {
+    bool dirty = false;
+    int r = -1;
+    ObjectReadOperation op;
+    op.is_dirty(&dirty, &r);
+    ASSERT_EQ(0, ioctx.operate("foo", &op, NULL));
+    ASSERT_TRUE(dirty);
+    ASSERT_EQ(0, r);
+  }
+
+  ioctx.close();
+  ASSERT_EQ(0, destroy_one_pool_pp(pool_name, cluster));
+}
+
 int main(int argc, char **argv)
 {
   ::testing::InitGoogleTest(&argc, argv);