Truncate the object size to 0 if the mainfest object is composed of chunks.
Signed-off-by: Myoungwon Oh <myoungwon.oh@samsung.com>
f(TIER_PROMOTE, __CEPH_OSD_OP(WR, DATA, 41), "tier-promote") \
f(UNSET_MANIFEST, __CEPH_OSD_OP(WR, DATA, 42), "unset-manifest") \
f(TIER_FLUSH, __CEPH_OSD_OP(CACHE, DATA, 43), "tier-flush") \
+ f(TIER_EVICT, __CEPH_OSD_OP(CACHE, DATA, 44), "tier-evict") \
\
/** attrs **/ \
/* read */ \
* updates.
*/
void tier_flush();
+ /**
+ * evict a manifest tier object to backing tier; will block racing
+ * updates.
+ */
+ void tier_evict();
};
/* IoCtx : This is a context in which we can perform I/O.
o->tier_flush();
}
+void librados::ObjectReadOperation::tier_evict()
+{
+ ceph_assert(impl);
+ ::ObjectOperation *o = &impl->o;
+ o->tier_evict();
+}
+
void librados::ObjectWriteOperation::set_redirect(const std::string& tgt_obj,
const IoCtx& tgt_ioctx,
uint64_t tgt_version,
op.op == CEPH_OSD_OP_SET_CHUNK ||
op.op == CEPH_OSD_OP_UNSET_MANIFEST ||
op.op == CEPH_OSD_OP_TIER_PROMOTE ||
- op.op == CEPH_OSD_OP_TIER_FLUSH) {
+ op.op == CEPH_OSD_OP_TIER_FLUSH ||
+ op.op == CEPH_OSD_OP_TIER_EVICT) {
return cache_result_t::NOOP;
}
}
case CEPH_OSD_OP_SET_CHUNK:
case CEPH_OSD_OP_TIER_PROMOTE:
case CEPH_OSD_OP_TIER_FLUSH:
+ case CEPH_OSD_OP_TIER_EVICT:
break;
default:
if (op.op & CEPH_OSD_OP_MODE_WR)
break;
+ case CEPH_OSD_OP_TIER_EVICT:
+ ++ctx->num_write;
+ result = 0;
+ {
+ if (pool.info.is_tier()) {
+ result = -EINVAL;
+ break;
+ }
+ if (!obs.exists) {
+ result = -ENOENT;
+ break;
+ }
+ if (get_osdmap()->require_osd_release < ceph_release_t::octopus) {
+ result = -EOPNOTSUPP;
+ break;
+ }
+ if (!obs.oi.has_manifest()) {
+ result = -EINVAL;
+ break;
+ }
+
+ // The chunks already has a reference, so it is just enough to invoke truncate if necessary
+ uint64_t chunk_length = 0;
+ for (auto p : obs.oi.manifest.chunk_map) {
+ chunk_length += p.second.length;
+ }
+ if (chunk_length == obs.oi.size) {
+ // truncate
+ for (auto p : obs.oi.manifest.chunk_map) {
+ p.second.set_flag(chunk_info_t::FLAG_MISSING);
+ }
+ t->truncate(obs.oi.soid, 0);
+ ctx->delta_stats.num_bytes -= obs.oi.size;
+ ctx->delta_stats.num_wr++;
+ oi.size = 0;
+ ctx->cache_operation = true;
+ }
+ osd->logger->inc(l_osd_tier_evict);
+ }
+
+ break;
+
case CEPH_OSD_OP_UNSET_MANIFEST:
++ctx->num_write;
result = 0;
add_op(CEPH_OSD_OP_TIER_FLUSH);
}
+ void tier_evict() {
+ add_op(CEPH_OSD_OP_TIER_EVICT);
+ }
+
void set_alloc_hint(uint64_t expected_object_size,
uint64_t expected_write_size,
uint32_t flags) {
" tier-promote <obj-name> promote the object to the base tier\n"
" unset-manifest <obj-name> unset redirect or chunked object\n"
" tier-flush <obj-name> flush the chunked object\n"
+" tier-evict <obj-name> evict the chunked object\n"
"\n"
"IMPORT AND EXPORT\n"
" export [filename]\n"
<< cpp_strerror(ret) << std::endl;
return 1;
}
+ } else if (strcmp(nargs[0], "tier-evict") == 0) {
+ if (!pool_name || nargs.size() < 2) {
+ usage(cerr);
+ return 1;
+ }
+ string oid(nargs[1]);
+
+ ObjectReadOperation op;
+ op.tier_evict();
+ librados::AioCompletion *completion =
+ librados::Rados::aio_create_completion();
+ io_ctx.aio_operate(oid.c_str(), completion, &op,
+ librados::OPERATION_IGNORE_CACHE |
+ librados::OPERATION_IGNORE_OVERLAY,
+ NULL);
+ completion->wait_for_complete();
+ ret = completion->get_return_value();
+ completion->release();
+ if (ret < 0) {
+ cerr << "error tier-evict " << pool_name << "/" << oid << " : "
+ << cpp_strerror(ret) << std::endl;
+ return 1;
+ }
} else if (strcmp(nargs[0], "export") == 0) {
// export [filename]
if (!pool_name || nargs.size() > 2) {