summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSage Weil <sage@inktank.com>2013-10-22 19:41:27 -0700
committerSage Weil <sage@inktank.com>2013-10-22 19:41:27 -0700
commit7583c3d941920ef5e6ad37c5ee740f9bf3854348 (patch)
tree255ccae655b1563240509853bad272515493c27b
parent85b9b38b19601436eae23e34ba2e6f9731170f5f (diff)
downloadceph-7583c3d941920ef5e6ad37c5ee740f9bf3854348.tar.gz
osd/ReplicatedPG: implement cache_evict
Signed-off-by: Sage Weil <sage@inktank.com>
-rw-r--r--src/osd/ReplicatedPG.cc25
-rw-r--r--src/osd/ReplicatedPG.h2
-rw-r--r--src/test/librados/tier.cc114
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();