mirror of
https://github.com/ceph/ceph
synced 2025-03-30 23:40:09 +00:00
Merge pull request #15199 from xiexingguo/wip-object-logic-size
osd: fine-grained statistics of logical object space usage Reviewed-by: Sage Weil <sage@redhat.com>
This commit is contained in:
commit
cd6b9830d1
@ -514,6 +514,48 @@ class btree_interval_set {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* build a subset of @other for given range [@start, @end)
|
||||
* E.g.:
|
||||
* subset_of([5~10,20~5], 0, 100) -> [5~10,20~5]
|
||||
* subset_of([5~10,20~5], 5, 25) -> [5~10,20~5]
|
||||
* subset_of([5~10,20~5], 1, 10) -> [5~5]
|
||||
* subset_of([5~10,20~5], 8, 24) -> [8~7, 20~4]
|
||||
*/
|
||||
void subset_of(const btree_interval_set &other, T start, T end) {
|
||||
assert(end >= start);
|
||||
clear();
|
||||
if (end == start) {
|
||||
return;
|
||||
}
|
||||
typename map_t::const_iterator p = other.find_inc(start);
|
||||
if (p == other.m.end())
|
||||
return;
|
||||
if (p->first < start) {
|
||||
if (p->first + p->second >= end) {
|
||||
insert(start, end - start);
|
||||
return;
|
||||
} else {
|
||||
insert(start, p->first + p->second - start);
|
||||
++p;
|
||||
}
|
||||
}
|
||||
while (p != other.m.end()) {
|
||||
assert(p->first >= start);
|
||||
if (p->first >= end) {
|
||||
return;
|
||||
}
|
||||
if (p->first + p->second >= end) {
|
||||
insert(p->first, end - p->first);
|
||||
return;
|
||||
} else {
|
||||
// whole
|
||||
insert(p->first, p->second);
|
||||
++p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* build a subset of @other, starting at or after @start, and including
|
||||
* @len worth of values, skipping holes. e.g.,
|
||||
|
@ -660,6 +660,48 @@ class interval_set {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* build a subset of @other for given rage [@start, @end)
|
||||
* E.g.:
|
||||
* subset_of([5~10,20~5], 0, 100) -> [5~10,20~5]
|
||||
* subset_of([5~10,20~5], 5, 25) -> [5~10,20~5]
|
||||
* subset_of([5~10,20~5], 1, 10) -> [5~5]
|
||||
* subset_of([5~10,20~5], 8, 24) -> [8~7, 20~4]
|
||||
*/
|
||||
void subset_of(const interval_set &other, T start, T end) {
|
||||
assert(end >= start);
|
||||
clear();
|
||||
if (end == start) {
|
||||
return;
|
||||
}
|
||||
typename std::map<T,T>::const_iterator p = other.find_inc(start);
|
||||
if (p == other.m.end())
|
||||
return;
|
||||
if (p->first < start) {
|
||||
if (p->first + p->second >= end) {
|
||||
insert(start, end - start);
|
||||
return;
|
||||
} else {
|
||||
insert(start, p->first + p->second - start);
|
||||
++p;
|
||||
}
|
||||
}
|
||||
while (p != other.m.end()) {
|
||||
assert(p->first >= start);
|
||||
if (p->first >= end) {
|
||||
return;
|
||||
}
|
||||
if (p->first + p->second >= end) {
|
||||
insert(p->first, end - p->first);
|
||||
return;
|
||||
} else {
|
||||
// whole
|
||||
insert(p->first, p->second);
|
||||
++p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* build a subset of @other, starting at or after @start, and including
|
||||
* @len worth of values, skipping holes. e.g.,
|
||||
|
@ -4416,8 +4416,21 @@ int PrimaryLogPG::do_checksum(OpContext *ctx, OSDOp& osd_op,
|
||||
if (op.checksum.offset == 0 && op.checksum.length == 0) {
|
||||
// zeroed offset+length implies checksum whole object
|
||||
op.checksum.length = oi.size;
|
||||
} else if (op.checksum.offset + op.checksum.length > oi.size) {
|
||||
return -EOVERFLOW;
|
||||
} else if (op.checksum.offset >= oi.size) {
|
||||
// read size was trimmed to zero, do nothing
|
||||
// see PrimaryLogPG::do_read
|
||||
return 0;
|
||||
} else if (op.extent.offset + op.extent.length > oi.size) {
|
||||
op.extent.length = oi.size - op.extent.offset;
|
||||
if (op.checksum.chunk_size > 0 &&
|
||||
op.checksum.length % op.checksum.chunk_size != 0) {
|
||||
dout(10) << __func__ << ": length (trimmed to 0x"
|
||||
<< std::hex << op.checksum.length
|
||||
<< ") not aligned to chunk size 0x"
|
||||
<< op.checksum.chunk_size << std::dec
|
||||
<< dendl;
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
Checksummer::CSumType csum_type;
|
||||
@ -4896,6 +4909,21 @@ int PrimaryLogPG::do_osd_ops(OpContext *ctx, vector<OSDOp>& ops)
|
||||
g_conf->get_val<bool>("osd_skip_data_digest");
|
||||
|
||||
PGTransaction* t = ctx->op_t.get();
|
||||
if (!oi.has_extents() &&
|
||||
get_osdmap()->require_osd_release >= CEPH_RELEASE_MIMIC) {
|
||||
assert(oi.extents.empty());
|
||||
// note that this is ok because:
|
||||
// 1. for reads, this should have no effect
|
||||
// 2. for writes, we check if this is a pre-mimic created object
|
||||
// (with FLAG_EXTENTS off). And if it is, we set FLAG_EXTENTS
|
||||
// and initialize extents with a whole entry - [0, oi.size) only
|
||||
// to make sure we have oi.extents.size() == oi.size at the very
|
||||
// beginning, which is necessary for backward compatibility.
|
||||
oi.set_flag(object_info_t::FLAG_EXTENTS);
|
||||
if (oi.size) {
|
||||
oi.extents.insert(0, oi.size);
|
||||
}
|
||||
}
|
||||
|
||||
dout(10) << "do_osd_op " << soid << " " << ops << dendl;
|
||||
|
||||
@ -5635,9 +5663,9 @@ int PrimaryLogPG::do_osd_ops(OpContext *ctx, vector<OSDOp>& ops)
|
||||
oi.truncate_seq = op.extent.truncate_seq;
|
||||
oi.truncate_size = op.extent.truncate_size;
|
||||
if (op.extent.truncate_size != oi.size) {
|
||||
ctx->delta_stats.num_bytes -= oi.size;
|
||||
ctx->delta_stats.num_bytes += op.extent.truncate_size;
|
||||
oi.size = op.extent.truncate_size;
|
||||
truncate_update_size_and_usage(ctx->delta_stats,
|
||||
oi,
|
||||
op.extent.truncate_size);
|
||||
}
|
||||
} else {
|
||||
dout(10) << " truncate_seq " << op.extent.truncate_seq << " > current " << seq
|
||||
@ -5747,6 +5775,15 @@ int PrimaryLogPG::do_osd_ops(OpContext *ctx, vector<OSDOp>& ops)
|
||||
ctx->modified_ranges.union_of(ch);
|
||||
ctx->delta_stats.num_wr++;
|
||||
oi.clear_data_digest();
|
||||
if (oi.has_extents()) {
|
||||
int64_t old_bytes = oi.extents.size();
|
||||
interval_set<uint64_t> to_remove;
|
||||
to_remove.subset_of(oi.extents, op.extent.offset,
|
||||
op.extent.offset + op.extent.length);
|
||||
oi.extents.subtract(to_remove);
|
||||
int64_t new_bytes = oi.extents.size();
|
||||
ctx->delta_stats.num_bytes += new_bytes - old_bytes;
|
||||
}
|
||||
} else {
|
||||
// no-op
|
||||
}
|
||||
@ -5825,9 +5862,9 @@ int PrimaryLogPG::do_osd_ops(OpContext *ctx, vector<OSDOp>& ops)
|
||||
ctx->modified_ranges.union_of(trim);
|
||||
}
|
||||
if (op.extent.offset != oi.size) {
|
||||
ctx->delta_stats.num_bytes -= oi.size;
|
||||
ctx->delta_stats.num_bytes += op.extent.offset;
|
||||
oi.size = op.extent.offset;
|
||||
truncate_update_size_and_usage(ctx->delta_stats,
|
||||
oi,
|
||||
op.extent.offset);
|
||||
}
|
||||
ctx->delta_stats.num_wr++;
|
||||
// do no set exists, or we will break above DELETE -> TRUNCATE munging.
|
||||
@ -6022,7 +6059,12 @@ int PrimaryLogPG::do_osd_ops(OpContext *ctx, vector<OSDOp>& ops)
|
||||
obs.oi.clear_omap_digest();
|
||||
obs.oi.clear_flag(object_info_t::FLAG_OMAP);
|
||||
}
|
||||
ctx->delta_stats.num_bytes -= oi.size;
|
||||
if (oi.has_extents()) {
|
||||
ctx->delta_stats.num_bytes -= oi.extents.size();
|
||||
oi.extents.clear();
|
||||
} else {
|
||||
ctx->delta_stats.num_bytes -= oi.size;
|
||||
}
|
||||
oi.size = 0;
|
||||
oi.new_object();
|
||||
oi.user_version = target_version;
|
||||
@ -6729,7 +6771,12 @@ inline int PrimaryLogPG::_delete_oid(
|
||||
assert(ctx->obc->ssc->snapset.clone_overlap.count(soid.snap));
|
||||
ctx->delta_stats.num_bytes -= ctx->obc->ssc->snapset.get_clone_bytes(soid.snap);
|
||||
} else {
|
||||
ctx->delta_stats.num_bytes -= oi.size;
|
||||
if (oi.has_extents()) {
|
||||
ctx->delta_stats.num_bytes -= oi.extents.size();
|
||||
oi.extents.clear();
|
||||
} else {
|
||||
ctx->delta_stats.num_bytes -= oi.size;
|
||||
}
|
||||
}
|
||||
oi.size = 0;
|
||||
oi.new_object();
|
||||
@ -6892,8 +6939,23 @@ int PrimaryLogPG::_rollback_to(OpContext *ctx, ceph_osd_op& op)
|
||||
|
||||
// Adjust the cached objectcontext
|
||||
maybe_create_new_object(ctx, true);
|
||||
ctx->delta_stats.num_bytes -= obs.oi.size;
|
||||
ctx->delta_stats.num_bytes += rollback_to->obs.oi.size;
|
||||
if (obs.oi.has_extents()) {
|
||||
ctx->delta_stats.num_bytes -= obs.oi.extents.size();
|
||||
obs.oi.extents.clear();
|
||||
} else {
|
||||
ctx->delta_stats.num_bytes -= obs.oi.size;
|
||||
}
|
||||
if (rollback_to->obs.oi.has_extents()) {
|
||||
ctx->delta_stats.num_bytes += rollback_to->obs.oi.extents.size();
|
||||
// transfer extents map too
|
||||
assert(obs.oi.has_extents());
|
||||
obs.oi.extents = rollback_to->obs.oi.extents;
|
||||
} else {
|
||||
ctx->delta_stats.num_bytes += rollback_to->obs.oi.size;
|
||||
if (obs.oi.has_extents() && rollback_to->obs.oi.size) {
|
||||
obs.oi.extents.insert(0, rollback_to->obs.oi.size);
|
||||
}
|
||||
}
|
||||
obs.oi.size = rollback_to->obs.oi.size;
|
||||
if (rollback_to->obs.oi.is_data_digest())
|
||||
obs.oi.set_data_digest(rollback_to->obs.oi.data_digest);
|
||||
@ -7103,14 +7165,56 @@ void PrimaryLogPG::write_update_size_and_usage(object_stat_sum_t& delta_stats, o
|
||||
modified.union_of(ch);
|
||||
if (write_full || offset + length > oi.size) {
|
||||
uint64_t new_size = offset + length;
|
||||
delta_stats.num_bytes -= oi.size;
|
||||
delta_stats.num_bytes += new_size;
|
||||
if (!oi.has_extents()) {
|
||||
delta_stats.num_bytes -= oi.size;
|
||||
delta_stats.num_bytes += new_size;
|
||||
}
|
||||
oi.size = new_size;
|
||||
}
|
||||
if (length && oi.has_extents()) {
|
||||
// count newly write bytes, exclude overwrites
|
||||
interval_set<uint64_t> ne;
|
||||
ne.insert(offset, length);
|
||||
interval_set<uint64_t> overlap;
|
||||
overlap.intersection_of(ne, oi.extents);
|
||||
ne.subtract(overlap);
|
||||
oi.extents.union_of(ne);
|
||||
delta_stats.num_bytes += ne.size();
|
||||
}
|
||||
delta_stats.num_wr++;
|
||||
delta_stats.num_wr_kb += SHIFT_ROUND_UP(length, 10);
|
||||
}
|
||||
|
||||
void PrimaryLogPG::truncate_update_size_and_usage(
|
||||
object_stat_sum_t& delta_stats,
|
||||
object_info_t& oi,
|
||||
uint64_t truncate_size)
|
||||
{
|
||||
if (oi.size == truncate_size) {
|
||||
// no change
|
||||
return;
|
||||
}
|
||||
if (oi.has_extents()) {
|
||||
int64_t old_bytes = oi.extents.size();
|
||||
if (truncate_size > oi.size) {
|
||||
// trunc up
|
||||
oi.extents.insert(oi.size, truncate_size - oi.size);
|
||||
} else {
|
||||
// trunc down
|
||||
interval_set<uint64_t> new_extents;
|
||||
new_extents.subset_of(oi.extents, 0, truncate_size);
|
||||
oi.extents.swap(new_extents);
|
||||
}
|
||||
int64_t new_bytes = oi.extents.size();
|
||||
delta_stats.num_bytes += new_bytes - old_bytes;
|
||||
} else {
|
||||
// fall back to old fashion
|
||||
delta_stats.num_bytes -= oi.size;
|
||||
delta_stats.num_bytes += truncate_size;
|
||||
}
|
||||
oi.size = truncate_size;
|
||||
}
|
||||
|
||||
void PrimaryLogPG::complete_disconnect_watches(
|
||||
ObjectContextRef obc,
|
||||
const list<watch_disconnect_t> &to_disconnect)
|
||||
@ -7663,6 +7767,12 @@ int PrimaryLogPG::do_copy_get(OpContext *ctx, bufferlist::iterator& bp,
|
||||
// but it works...
|
||||
pg_log.get_log().get_object_reqids(ctx->obc->obs.oi.soid, 10, &reply_obj.reqids);
|
||||
dout(20) << " got reqids" << dendl;
|
||||
if (oi.has_extents()) {
|
||||
// note that we might call this multiple times
|
||||
// include extents only in the final step to make extents.insert happy
|
||||
reply_obj.flags |= object_copy_data_t::FLAG_EXTENTS;
|
||||
reply_obj.extents = oi.extents;
|
||||
}
|
||||
}
|
||||
|
||||
dout(20) << " cursor.is_complete=" << cursor.is_complete()
|
||||
@ -7788,6 +7898,7 @@ void PrimaryLogPG::_copy_some(ObjectContextRef obc, CopyOpRef cop)
|
||||
&cop->results.reqids,
|
||||
&cop->results.truncate_seq,
|
||||
&cop->results.truncate_size,
|
||||
&cop->results.extents,
|
||||
&cop->rval);
|
||||
op.set_last_op_flags(cop->src_obj_fadvise_flags);
|
||||
|
||||
@ -8130,11 +8241,12 @@ void PrimaryLogPG::finish_copyfrom(CopyFromCallback *cb)
|
||||
ch.insert(0, obs.oi.size);
|
||||
ctx->modified_ranges.union_of(ch);
|
||||
|
||||
if (cb->get_data_size() != obs.oi.size) {
|
||||
ctx->delta_stats.num_bytes -= obs.oi.size;
|
||||
obs.oi.size = cb->get_data_size();
|
||||
ctx->delta_stats.num_bytes += obs.oi.size;
|
||||
}
|
||||
ctx->delta_stats.num_bytes -= obs.oi.has_extents() ?
|
||||
obs.oi.extents.size() : obs.oi.size;
|
||||
obs.oi.clear_flag(object_info_t::FLAG_EXTENTS);
|
||||
obs.oi.extents.clear();
|
||||
obs.oi.size = cb->get_data_size();
|
||||
ctx->delta_stats.num_bytes += obs.oi.size;
|
||||
ctx->delta_stats.num_wr++;
|
||||
ctx->delta_stats.num_wr_kb += SHIFT_ROUND_UP(obs.oi.size, 10);
|
||||
|
||||
@ -8298,6 +8410,10 @@ void PrimaryLogPG::finish_promote(int r, CopyResults *results,
|
||||
tctx->new_obs.oi.set_omap_digest(results->omap_digest);
|
||||
tctx->new_obs.oi.truncate_seq = results->truncate_seq;
|
||||
tctx->new_obs.oi.truncate_size = results->truncate_size;
|
||||
if (results->has_extents()) {
|
||||
tctx->new_obs.oi.set_flag(object_info_t::FLAG_EXTENTS);
|
||||
tctx->new_obs.oi.extents = results->extents;
|
||||
}
|
||||
|
||||
if (soid.snap != CEPH_NOSNAP) {
|
||||
assert(obc->ssc->snapset.clone_snaps.count(soid.snap));
|
||||
@ -8308,7 +8424,8 @@ void PrimaryLogPG::finish_promote(int r, CopyResults *results,
|
||||
|
||||
tctx->delta_stats.num_bytes += obc->ssc->snapset.get_clone_bytes(soid.snap);
|
||||
} else {
|
||||
tctx->delta_stats.num_bytes += results->object_size;
|
||||
tctx->delta_stats.num_bytes += results->has_extents() ?
|
||||
results->extents.size() : results->object_size;
|
||||
}
|
||||
}
|
||||
|
||||
@ -9814,7 +9931,8 @@ void PrimaryLogPG::add_object_context_to_pg_stat(ObjectContextRef obc, pg_stat_t
|
||||
assert(!oi.soid.is_snapdir());
|
||||
|
||||
object_stat_sum_t stat;
|
||||
stat.num_bytes += oi.size;
|
||||
stat.num_bytes += oi.has_extents() ?
|
||||
oi.extents.size() : oi.size;
|
||||
stat.num_objects++;
|
||||
if (oi.is_dirty())
|
||||
stat.num_objects_dirty++;
|
||||
@ -12284,6 +12402,9 @@ void PrimaryLogPG::hit_set_persist()
|
||||
|
||||
ctx->delta_stats.num_objects++;
|
||||
ctx->delta_stats.num_objects_hit_set_archive++;
|
||||
// we do not use extents for usage tracking
|
||||
// of hit_set_archive objects, for now!
|
||||
assert(!obc->obs.oi.has_extents());
|
||||
ctx->delta_stats.num_bytes += bl.length();
|
||||
ctx->delta_stats.num_bytes_hit_set_archive += bl.length();
|
||||
|
||||
@ -12349,6 +12470,7 @@ void PrimaryLogPG::hit_set_trim(OpContextUPtr &ctx, unsigned max)
|
||||
assert(obc);
|
||||
--ctx->delta_stats.num_objects;
|
||||
--ctx->delta_stats.num_objects_hit_set_archive;
|
||||
assert(!obc->obs.oi.has_extents());
|
||||
ctx->delta_stats.num_bytes -= obc->obs.oi.size;
|
||||
ctx->delta_stats.num_bytes_hit_set_archive -= obc->obs.oi.size;
|
||||
}
|
||||
@ -13305,7 +13427,8 @@ void PrimaryLogPG::scrub_snapshot_metadata(
|
||||
|
||||
// A clone num_bytes will be added later when we have snapset
|
||||
if (!soid.is_snap()) {
|
||||
stat.num_bytes += oi->size;
|
||||
stat.num_bytes += oi->has_extents() ?
|
||||
oi->extents.size() : oi->size;
|
||||
}
|
||||
if (soid.nspace == cct->_conf->osd_hit_set_namespace)
|
||||
stat.num_bytes_hit_set_archive += oi->size;
|
||||
|
@ -95,12 +95,16 @@ public:
|
||||
map<string, bufferlist> attrs; // xattrs
|
||||
uint64_t truncate_seq;
|
||||
uint64_t truncate_size;
|
||||
interval_set<uint64_t> extents; // object logical extents map
|
||||
bool is_data_digest() {
|
||||
return flags & object_copy_data_t::FLAG_DATA_DIGEST;
|
||||
}
|
||||
bool is_omap_digest() {
|
||||
return flags & object_copy_data_t::FLAG_OMAP_DIGEST;
|
||||
}
|
||||
bool has_extents() {
|
||||
return flags & object_copy_data_t::FLAG_EXTENTS;
|
||||
}
|
||||
CopyResults()
|
||||
: object_size(0), started_temp_obj(false),
|
||||
user_version(0),
|
||||
@ -1106,6 +1110,10 @@ protected:
|
||||
void write_update_size_and_usage(object_stat_sum_t& stats, object_info_t& oi,
|
||||
interval_set<uint64_t>& modified, uint64_t offset,
|
||||
uint64_t length, bool write_full=false);
|
||||
void truncate_update_size_and_usage(
|
||||
object_stat_sum_t& delta_stats,
|
||||
object_info_t& oi,
|
||||
uint64_t truncate_size);
|
||||
|
||||
enum class cache_result_t {
|
||||
NOOP,
|
||||
|
@ -4250,7 +4250,7 @@ void object_copy_cursor_t::generate_test_instances(list<object_copy_cursor_t*>&
|
||||
|
||||
void object_copy_data_t::encode(bufferlist& bl, uint64_t features) const
|
||||
{
|
||||
ENCODE_START(7, 5, bl);
|
||||
ENCODE_START(8, 5, bl);
|
||||
::encode(size, bl);
|
||||
::encode(mtime, bl);
|
||||
::encode(attrs, bl);
|
||||
@ -4266,12 +4266,13 @@ void object_copy_data_t::encode(bufferlist& bl, uint64_t features) const
|
||||
::encode(reqids, bl);
|
||||
::encode(truncate_seq, bl);
|
||||
::encode(truncate_size, bl);
|
||||
::encode(extents, bl);
|
||||
ENCODE_FINISH(bl);
|
||||
}
|
||||
|
||||
void object_copy_data_t::decode(bufferlist::iterator& bl)
|
||||
{
|
||||
DECODE_START(7, bl);
|
||||
DECODE_START(8, bl);
|
||||
if (struct_v < 5) {
|
||||
// old
|
||||
::decode(size, bl);
|
||||
@ -4327,6 +4328,9 @@ void object_copy_data_t::decode(bufferlist::iterator& bl)
|
||||
::decode(truncate_seq, bl);
|
||||
::decode(truncate_size, bl);
|
||||
}
|
||||
if (struct_v >= 8) {
|
||||
::decode(extents, bl);
|
||||
}
|
||||
}
|
||||
DECODE_FINISH(bl);
|
||||
}
|
||||
@ -4361,6 +4365,7 @@ void object_copy_data_t::generate_test_instances(list<object_copy_data_t*>& o)
|
||||
o.back()->omap_header.append("this is an omap header");
|
||||
o.back()->snaps.push_back(123);
|
||||
o.back()->reqids.push_back(make_pair(osd_reqid_t(), version_t()));
|
||||
o.back()->extents.insert(0, 123);
|
||||
}
|
||||
|
||||
void object_copy_data_t::dump(Formatter *f) const
|
||||
@ -4900,7 +4905,7 @@ void object_info_t::encode(bufferlist& bl, uint64_t features) const
|
||||
++i) {
|
||||
old_watchers.insert(make_pair(i->first.second, i->second));
|
||||
}
|
||||
ENCODE_START(17, 8, bl);
|
||||
ENCODE_START(18, 8, bl);
|
||||
::encode(soid, bl);
|
||||
::encode(myoloc, bl); //Retained for compatibility
|
||||
::encode((__u32)0, bl); // was category, no longer used
|
||||
@ -4934,13 +4939,14 @@ void object_info_t::encode(bufferlist& bl, uint64_t features) const
|
||||
if (has_manifest()) {
|
||||
::encode(manifest, bl);
|
||||
}
|
||||
::encode(extents, bl);
|
||||
ENCODE_FINISH(bl);
|
||||
}
|
||||
|
||||
void object_info_t::decode(bufferlist::iterator& bl)
|
||||
{
|
||||
object_locator_t myoloc;
|
||||
DECODE_START_LEGACY_COMPAT_LEN(17, 8, 8, bl);
|
||||
DECODE_START_LEGACY_COMPAT_LEN(18, 8, 8, bl);
|
||||
map<entity_name_t, watch_info_t> old_watchers;
|
||||
::decode(soid, bl);
|
||||
::decode(myoloc, bl);
|
||||
@ -5028,6 +5034,9 @@ void object_info_t::decode(bufferlist::iterator& bl)
|
||||
::decode(manifest, bl);
|
||||
}
|
||||
}
|
||||
if (struct_v >= 18) {
|
||||
::decode(extents, bl);
|
||||
}
|
||||
DECODE_FINISH(bl);
|
||||
}
|
||||
|
||||
@ -5053,6 +5062,15 @@ void object_info_t::dump(Formatter *f) const
|
||||
f->dump_unsigned("expected_write_size", expected_write_size);
|
||||
f->dump_unsigned("alloc_hint_flags", alloc_hint_flags);
|
||||
f->dump_object("manifest", manifest);
|
||||
f->open_array_section("extents");
|
||||
for (interval_set<uint64_t>::const_iterator p = extents.begin();
|
||||
p != extents.end(); ++p) {
|
||||
f->open_object_section("extent");
|
||||
f->dump_unsigned("offset", p.get_start());
|
||||
f->dump_unsigned("length", p.get_len());
|
||||
f->close_section();
|
||||
}
|
||||
f->close_section();
|
||||
f->open_object_section("watchers");
|
||||
for (map<pair<uint64_t, entity_name_t>,watch_info_t>::const_iterator p =
|
||||
watchers.begin(); p != watchers.end(); ++p) {
|
||||
|
@ -4283,6 +4283,7 @@ struct object_copy_data_t {
|
||||
enum {
|
||||
FLAG_DATA_DIGEST = 1<<0,
|
||||
FLAG_OMAP_DIGEST = 1<<1,
|
||||
FLAG_EXTENTS = 1<<2,
|
||||
};
|
||||
object_copy_cursor_t cursor;
|
||||
uint64_t size;
|
||||
@ -4305,6 +4306,9 @@ struct object_copy_data_t {
|
||||
uint64_t truncate_seq;
|
||||
uint64_t truncate_size;
|
||||
|
||||
///< object logical extents map
|
||||
interval_set<uint64_t> extents;
|
||||
|
||||
public:
|
||||
object_copy_data_t() :
|
||||
size((uint64_t)-1), data_digest(-1),
|
||||
@ -4593,16 +4597,16 @@ struct object_info_t {
|
||||
// note: these are currently encoded into a total 16 bits; see
|
||||
// encode()/decode() for the weirdness.
|
||||
typedef enum {
|
||||
FLAG_LOST = 1<<0,
|
||||
FLAG_WHITEOUT = 1<<1, // object logically does not exist
|
||||
FLAG_DIRTY = 1<<2, // object has been modified since last flushed or undirtied
|
||||
FLAG_OMAP = 1 << 3, // has (or may have) some/any omap data
|
||||
FLAG_DATA_DIGEST = 1 << 4, // has data crc
|
||||
FLAG_OMAP_DIGEST = 1 << 5, // has omap crc
|
||||
FLAG_CACHE_PIN = 1 << 6, // pin the object in cache tier
|
||||
FLAG_MANIFEST = 1 << 7, // has manifest
|
||||
// ...
|
||||
FLAG_USES_TMAP = 1<<8, // deprecated; no longer used.
|
||||
FLAG_LOST = 1<<0,
|
||||
FLAG_WHITEOUT = 1<<1, // object logically does not exist
|
||||
FLAG_DIRTY = 1<<2, // object has been modified since last flushed or undirtied
|
||||
FLAG_OMAP = 1<<3, // has (or may have) some/any omap data
|
||||
FLAG_DATA_DIGEST = 1<<4, // has data crc
|
||||
FLAG_OMAP_DIGEST = 1<<5, // has omap crc
|
||||
FLAG_CACHE_PIN = 1<<6, // pin the object in cache tier
|
||||
FLAG_MANIFEST = 1<<7, // has manifest
|
||||
FLAG_USES_TMAP = 1<<8, // deprecated; no longer used
|
||||
FLAG_EXTENTS = 1<<9, // logical extents map is valid
|
||||
} flag_t;
|
||||
|
||||
flag_t flags;
|
||||
@ -4627,6 +4631,8 @@ struct object_info_t {
|
||||
s += "|cache_pin";
|
||||
if (flags & FLAG_MANIFEST)
|
||||
s += "|manifest";
|
||||
if (flags & FLAG_EXTENTS)
|
||||
s += "|extents";
|
||||
if (s.length())
|
||||
return s.substr(1);
|
||||
return s;
|
||||
@ -4648,6 +4654,7 @@ struct object_info_t {
|
||||
uint32_t alloc_hint_flags;
|
||||
|
||||
struct object_manifest_t manifest;
|
||||
interval_set<uint64_t> extents; // deduplicated logical extents map
|
||||
|
||||
void copy_user_bits(const object_info_t& other);
|
||||
|
||||
@ -4684,7 +4691,9 @@ struct object_info_t {
|
||||
bool has_manifest() const {
|
||||
return test_flag(FLAG_MANIFEST);
|
||||
}
|
||||
|
||||
bool has_extents() const {
|
||||
return test_flag(FLAG_EXTENTS);
|
||||
}
|
||||
void set_data_digest(__u32 d) {
|
||||
set_flag(FLAG_DATA_DIGEST);
|
||||
data_digest = d;
|
||||
|
@ -730,6 +730,7 @@ struct ObjectOperation {
|
||||
mempool::osd_pglog::vector<pair<osd_reqid_t, version_t> > *out_reqids;
|
||||
uint64_t *out_truncate_seq;
|
||||
uint64_t *out_truncate_size;
|
||||
interval_set<uint64_t> *out_extents;
|
||||
int *prval;
|
||||
C_ObjectOperation_copyget(object_copy_cursor_t *c,
|
||||
uint64_t *s,
|
||||
@ -745,6 +746,7 @@ struct ObjectOperation {
|
||||
mempool::osd_pglog::vector<pair<osd_reqid_t, version_t> > *oreqids,
|
||||
uint64_t *otseq,
|
||||
uint64_t *otsize,
|
||||
interval_set<uint64_t> *otextents,
|
||||
int *r)
|
||||
: cursor(c),
|
||||
out_size(s), out_mtime(m),
|
||||
@ -754,6 +756,7 @@ struct ObjectOperation {
|
||||
out_reqids(oreqids),
|
||||
out_truncate_seq(otseq),
|
||||
out_truncate_size(otsize),
|
||||
out_extents(otextents),
|
||||
prval(r) {}
|
||||
void finish(int r) override {
|
||||
// reqids are copied on ENOENT
|
||||
@ -796,6 +799,9 @@ struct ObjectOperation {
|
||||
*out_truncate_seq = copy_reply.truncate_seq;
|
||||
if (out_truncate_size)
|
||||
*out_truncate_size = copy_reply.truncate_size;
|
||||
if (out_extents) {
|
||||
*out_extents = copy_reply.extents;
|
||||
}
|
||||
*cursor = copy_reply.cursor;
|
||||
} catch (buffer::error& e) {
|
||||
if (prval)
|
||||
@ -820,6 +826,7 @@ struct ObjectOperation {
|
||||
mempool::osd_pglog::vector<pair<osd_reqid_t, version_t> > *out_reqids,
|
||||
uint64_t *truncate_seq,
|
||||
uint64_t *truncate_size,
|
||||
interval_set<uint64_t> *extents,
|
||||
int *prval) {
|
||||
OSDOp& osd_op = add_op(CEPH_OSD_OP_COPY_GET);
|
||||
osd_op.op.copy_get.max = max;
|
||||
@ -833,7 +840,7 @@ struct ObjectOperation {
|
||||
out_omap_data, out_snaps, out_snap_seq,
|
||||
out_flags, out_data_digest,
|
||||
out_omap_digest, out_reqids, truncate_seq,
|
||||
truncate_size, prval);
|
||||
truncate_size, extents, prval);
|
||||
out_bl[p] = &h->bl;
|
||||
out_handler[p] = h;
|
||||
}
|
||||
|
@ -557,6 +557,53 @@ TYPED_TEST(IntervalSetTest, subset_of) {
|
||||
iset1.insert( 50, 5);
|
||||
iset2.insert( 55, 2);
|
||||
ASSERT_FALSE(iset1.subset_of(iset2));
|
||||
|
||||
ISet iset3, iset4, expected;
|
||||
iset3.insert(5, 10);
|
||||
iset3.insert(20, 5);
|
||||
|
||||
iset4.subset_of(iset3, 0, 100);
|
||||
expected.insert(5, 10);
|
||||
expected.insert(20, 5);
|
||||
ASSERT_TRUE(iset4 == expected);
|
||||
|
||||
iset4.clear();
|
||||
iset4.subset_of(iset3, 5, 25);
|
||||
ASSERT_TRUE(iset4 == expected);
|
||||
|
||||
iset4.clear();
|
||||
iset4.subset_of(iset3, 1, 10);
|
||||
expected.clear();
|
||||
expected.insert(5, 5);
|
||||
ASSERT_TRUE(iset4 == expected);
|
||||
|
||||
iset4.clear();
|
||||
iset4.subset_of(iset3, 8, 24);
|
||||
expected.clear();
|
||||
expected.insert(8, 7);
|
||||
expected.insert(20, 4);
|
||||
ASSERT_TRUE(iset4 == expected);
|
||||
|
||||
iset4.clear();
|
||||
iset4.subset_of(iset3, 0, 0);
|
||||
expected.clear();
|
||||
ASSERT_TRUE(iset4 == expected);
|
||||
|
||||
iset4.clear();
|
||||
iset4.subset_of(iset3, 0, 1);
|
||||
ASSERT_TRUE(iset4 == expected);
|
||||
|
||||
iset4.clear();
|
||||
iset4.subset_of(iset3, 0, 5);
|
||||
ASSERT_TRUE(iset4 == expected);
|
||||
|
||||
iset4.clear();
|
||||
iset4.subset_of(iset3, 25, 30);
|
||||
ASSERT_TRUE(iset4 == expected);
|
||||
|
||||
iset4.clear();
|
||||
iset4.subset_of(iset3, 26, 40);
|
||||
ASSERT_TRUE(iset4 == expected);
|
||||
}
|
||||
|
||||
TYPED_TEST(IntervalSetTest, span_of) {
|
||||
@ -592,4 +639,4 @@ TYPED_TEST(IntervalSetTest, span_of) {
|
||||
iset1.span_of( iset2, 100, 5 );
|
||||
ASSERT_EQ( iset1.num_intervals(), 0);
|
||||
ASSERT_EQ( iset1.size(), 0);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user