diff options
author | Sage Weil <sage@inktank.com> | 2013-10-22 19:41:27 -0700 |
---|---|---|
committer | Sage Weil <sage@inktank.com> | 2013-10-22 19:41:27 -0700 |
commit | 7583c3d941920ef5e6ad37c5ee740f9bf3854348 (patch) | |
tree | 255ccae655b1563240509853bad272515493c27b | |
parent | 85b9b38b19601436eae23e34ba2e6f9731170f5f (diff) | |
download | ceph-7583c3d941920ef5e6ad37c5ee740f9bf3854348.tar.gz |
osd/ReplicatedPG: implement cache_evict
Signed-off-by: Sage Weil <sage@inktank.com>
-rw-r--r-- | src/osd/ReplicatedPG.cc | 25 | ||||
-rw-r--r-- | src/osd/ReplicatedPG.h | 2 | ||||
-rw-r--r-- | src/test/librados/tier.cc | 114 |
3 files changed, 135 insertions, 6 deletions
diff --git a/src/osd/ReplicatedPG.cc b/src/osd/ReplicatedPG.cc index a055271afbb..64896d94b5f 100644 --- a/src/osd/ReplicatedPG.cc +++ b/src/osd/ReplicatedPG.cc @@ -2747,6 +2747,21 @@ int ReplicatedPG::do_osd_ops(OpContext *ctx, vector<OSDOp>& ops) } break; + case CEPH_OSD_OP_CACHE_EVICT: + ++ctx->num_write; + { + if (pool.info.cache_mode == pg_pool_t::CACHEMODE_NONE) { + result = -EINVAL; + break; + } + if (oi.is_dirty()) { + result = -EBUSY; + break; + } + result = _delete_head(ctx, true); + } + break; + case CEPH_OSD_OP_GETXATTR: ++ctx->num_read; { @@ -3235,7 +3250,7 @@ int ReplicatedPG::do_osd_ops(OpContext *ctx, vector<OSDOp>& ops) // Cannot delete an object with watchers result = -EBUSY; } else { - result = _delete_head(ctx); + result = _delete_head(ctx, false); } break; @@ -3781,7 +3796,7 @@ int ReplicatedPG::_get_tmap(OpContext *ctx, return 0; } -inline int ReplicatedPG::_delete_head(OpContext *ctx) +inline int ReplicatedPG::_delete_head(OpContext *ctx, bool no_whiteout) { SnapSet& snapset = ctx->new_snapset; ObjectState& obs = ctx->new_obs; @@ -3789,7 +3804,7 @@ inline int ReplicatedPG::_delete_head(OpContext *ctx) const hobject_t& soid = oi.soid; ObjectStore::Transaction& t = ctx->op_t; - if (!obs.exists || obs.oi.is_whiteout()) + if (!obs.exists || (obs.oi.is_whiteout() && !no_whiteout)) return -ENOENT; if (oi.size > 0) { @@ -3803,7 +3818,7 @@ inline int ReplicatedPG::_delete_head(OpContext *ctx) oi.size = 0; // cache: writeback: set whiteout on delete? - if (pool.info.cache_mode == pg_pool_t::CACHEMODE_WRITEBACK) { + if (pool.info.cache_mode == pg_pool_t::CACHEMODE_WRITEBACK && !no_whiteout) { dout(20) << __func__ << " setting whiteout on " << soid << dendl; oi.set_flag(object_info_t::FLAG_WHITEOUT); t.truncate(coll, soid, 0); @@ -3844,7 +3859,7 @@ int ReplicatedPG::_rollback_to(OpContext *ctx, ceph_osd_op& op) // Cannot delete an object with watchers ret = -EBUSY; } else { - _delete_head(ctx); + _delete_head(ctx, false); ret = 0; } } else if (-EAGAIN == ret) { diff --git a/src/osd/ReplicatedPG.h b/src/osd/ReplicatedPG.h index 0a537889746..6b61d8adeaa 100644 --- a/src/osd/ReplicatedPG.h +++ b/src/osd/ReplicatedPG.h @@ -1198,7 +1198,7 @@ private: int _get_tmap(OpContext *ctx, map<string, bufferlist> *out, bufferlist *header); - int _delete_head(OpContext *ctx); + int _delete_head(OpContext *ctx, bool no_whiteout); int _rollback_to(OpContext *ctx, ceph_osd_op& op); public: bool same_for_read_since(epoch_t e); diff --git a/src/test/librados/tier.cc b/src/test/librados/tier.cc index a97dc72dd80..1a9e9c0e6a6 100644 --- a/src/test/librados/tier.cc +++ b/src/test/librados/tier.cc @@ -249,6 +249,120 @@ TEST(LibRadosTier, Whiteout) { ASSERT_EQ(0, destroy_one_pool_pp(base_pool_name, cluster)); } +TEST(LibRadosTier, Evict) { + Rados cluster; + std::string base_pool_name = get_temp_pool_name(); + std::string cache_pool_name = base_pool_name + "-cache"; + ASSERT_EQ("", create_one_pool_pp(base_pool_name, cluster)); + ASSERT_EQ(0, cluster.pool_create(cache_pool_name.c_str())); + IoCtx cache_ioctx; + ASSERT_EQ(0, cluster.ioctx_create(cache_pool_name.c_str(), cache_ioctx)); + IoCtx base_ioctx; + ASSERT_EQ(0, cluster.ioctx_create(base_pool_name.c_str(), base_ioctx)); + + // create object + { + bufferlist bl; + bl.append("hi there"); + ObjectWriteOperation op; + op.write_full(bl); + ASSERT_EQ(0, base_ioctx.operate("foo", &op)); + } + + // configure cache + bufferlist inbl; + ASSERT_EQ(0, cluster.mon_command( + "{\"prefix\": \"osd tier add\", \"pool\": \"" + base_pool_name + + "\", \"tierpool\": \"" + cache_pool_name + "\"}", + inbl, NULL, NULL)); + ASSERT_EQ(0, cluster.mon_command( + "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + base_pool_name + + "\", \"overlaypool\": \"" + cache_pool_name + "\"}", + inbl, NULL, NULL)); + ASSERT_EQ(0, cluster.mon_command( + "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name + + "\", \"mode\": \"writeback\"}", + inbl, NULL, NULL)); + + // wait for maps to settle + cluster.wait_for_latest_map(); + + // read, trigger a promote + { + bufferlist bl; + ASSERT_EQ(1, base_ioctx.read("foo", bl, 1, 0)); + } + + // read, trigger a whiteout, and a dirty object + { + bufferlist bl; + ASSERT_EQ(-ENOENT, base_ioctx.read("bar", bl, 1, 0)); + ASSERT_EQ(-ENOENT, base_ioctx.read("bar", bl, 1, 0)); + ASSERT_EQ(0, base_ioctx.write("bar", bl, bl.length(), 0)); + } + + // verify the object is present in the cache tier + { + ObjectIterator it = cache_ioctx.objects_begin(); + ASSERT_TRUE(it != cache_ioctx.objects_end()); + ASSERT_TRUE(it->first == string("foo") || it->first == string("bar")); + ++it; + ASSERT_TRUE(it->first == string("foo") || it->first == string("bar")); + ++it; + ASSERT_TRUE(it == cache_ioctx.objects_end()); + } + + // evict + { + ObjectWriteOperation op; + op.cache_evict(); + librados::AioCompletion *completion = cluster.aio_create_completion(); + ASSERT_EQ(0, cache_ioctx.aio_operate( + "foo", completion, &op, librados::OPERATION_IGNORE_OVERLAY)); + completion->wait_for_safe(); + ASSERT_EQ(0, completion->get_return_value()); + completion->release(); + } + { + ObjectWriteOperation op; + op.cache_evict(); + librados::AioCompletion *completion = cluster.aio_create_completion(); + ASSERT_EQ(0, cache_ioctx.aio_operate( + "fooberdoodle", completion, &op, + librados::OPERATION_IGNORE_OVERLAY)); + completion->wait_for_safe(); + ASSERT_EQ(-ENOENT, completion->get_return_value()); + completion->release(); + } + { + ObjectWriteOperation op; + op.cache_evict(); + librados::AioCompletion *completion = cluster.aio_create_completion(); + ASSERT_EQ(0, cache_ioctx.aio_operate( + "bar", completion, &op, + librados::OPERATION_IGNORE_OVERLAY)); + completion->wait_for_safe(); + ASSERT_EQ(-EBUSY, completion->get_return_value()); + completion->release(); + } + + // tear down tiers + ASSERT_EQ(0, cluster.mon_command( + "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + base_pool_name + + "\"}", + inbl, NULL, NULL)); + ASSERT_EQ(0, cluster.mon_command( + "{\"prefix\": \"osd tier remove\", \"pool\": \"" + base_pool_name + + "\", \"tierpool\": \"" + cache_pool_name + "\"}", + inbl, NULL, NULL)); + + base_ioctx.close(); + cache_ioctx.close(); + + cluster.pool_delete(cache_pool_name.c_str()); + ASSERT_EQ(0, destroy_one_pool_pp(base_pool_name, cluster)); +} + TEST(LibRadosTier, HitSetNone) { Rados cluster; std::string pool_name = get_temp_pool_name(); |