plb.add_u64_counter(l_objectcacher_cache_ops_hit, "cache_ops_hit");
plb.add_u64_counter(l_objectcacher_cache_ops_miss, "cache_ops_miss");
+ plb.add_u64_counter(l_objectcacher_cache_ops_partial_hit, "cache_ops_partial_hit");
+ plb.add_u64_counter(l_objectcacher_cache_ops_wait_cow, "cache_ops_wait_cow");
plb.add_u64_counter(l_objectcacher_cache_bytes_hit, "cache_bytes_hit");
+ plb.add_u64_counter(l_objectcacher_cache_bytes_partial_hit, "cache_bytes_partial_hit");
plb.add_u64_counter(l_objectcacher_cache_bytes_miss, "cache_bytes_miss");
+ plb.add_u64_counter(l_objectcacher_cache_bytes_rx, "cache_bytes_rx");
+ plb.add_u64_counter(l_objectcacher_cache_bytes_wait_cow, "cache_bytes_wait_cow");
plb.add_u64_counter(l_objectcacher_data_read, "data_read");
plb.add_u64_counter(l_objectcacher_data_written, "data_written");
plb.add_u64_counter(l_objectcacher_data_flushed, "data_flushed");
int error = 0;
list<BufferHead*> hit_ls;
uint64_t bytes_in_cache = 0;
- uint64_t bytes_not_in_cache = 0;
+ uint64_t bytes_missing = 0;
+ uint64_t bytes_rx = 0;
uint64_t total_bytes_read = 0;
map<uint64_t, bufferlist> stripe_map; // final buffer offset -> substring
for (vector<ObjectExtent>::iterator ex_it = rd->extents.begin();
ex_it != rd->extents.end();
++ex_it) {
- ldout(cct, 10) << "readx " << *ex_it << dendl;
-
total_bytes_read += ex_it->length;
+ }
+
+ for (vector<ObjectExtent>::iterator ex_it = rd->extents.begin();
+ ex_it != rd->extents.end();
+ ++ex_it) {
+ ldout(cct, 10) << "readx " << *ex_it << dendl;
// get Object cache
sobject_t soid(ex_it->oid, rd->snap);
if (wait) {
ldout(cct, 10) << "readx waiting on tid " << o->last_write_tid << " on " << *o << dendl;
o->waitfor_commit[o->last_write_tid].push_back(new C_RetryRead(this, rd, oset, onfinish));
- // FIXME: perfcounter!
+ if (perfcounter && external_call) {
+ perfcounter->inc(l_objectcacher_data_read, total_bytes_read);
+ perfcounter->inc(l_objectcacher_cache_bytes_wait_cow, total_bytes_read);
+ perfcounter->inc(l_objectcacher_cache_ops_wait_cow);
+ }
return 0;
}
}
if (allzero) {
ldout(cct, 10) << "readx ob has all zero|rx, returning ENOENT" << dendl;
delete rd;
+ if (perfcounter && external_call) {
+ perfcounter->inc(l_objectcacher_data_read, total_bytes_read);
+ perfcounter->inc(l_objectcacher_cache_bytes_hit, total_bytes_read);
+ perfcounter->inc(l_objectcacher_cache_ops_hit);
+ }
return -ENOENT;
}
}
<< " off " << bh_it->first << dendl;
bh_it->second->waitfor_read[bh_it->first].push_back( new C_RetryRead(this, rd, oset, onfinish) );
}
- bytes_not_in_cache += bh_it->second->length();
}
+ bytes_missing += bh_it->second->overlap_size(bh_it->first, ex_it->offset + ex_it->length);
success = false;
}
<< " off " << bh_it->first << dendl;
bh_it->second->waitfor_read[bh_it->first].push_back( new C_RetryRead(this, rd, oset, onfinish) );
}
- bytes_not_in_cache += bh_it->second->length();
+ bytes_rx += bh_it->second->overlap_size(bh_it->first, ex_it->offset + ex_it->length);
success = false;
}
+
+ // Count the bytes that were available in the cache, so we can track partial hits
+ for (map<loff_t, BufferHead*>::iterator bh_it = hits.begin();
+ bh_it != hits.end();
+ ++bh_it) {
+ bytes_in_cache += bh_it->second->overlap_size(bh_it->first, ex_it->offset + ex_it->length);
+ }
} else {
assert(!hits.empty());
if (bh_it->second->is_error() && bh_it->second->error)
error = bh_it->second->error;
hit_ls.push_back(bh_it->second);
- bytes_in_cache += bh_it->second->length();
}
// create reverse map of buffer offset -> object for the eventual result.
stripe_map[f_it->first].claim_append(bit);
}
+ bytes_in_cache += len;
opos += len;
bhoff += len;
foff += len;
bhit != hit_ls.end();
++bhit)
touch_bh(*bhit);
-
+
+ assert(bytes_in_cache + bytes_missing + bytes_rx == total_bytes_read);
+
if (!success) {
if (perfcounter && external_call) {
perfcounter->inc(l_objectcacher_data_read, total_bytes_read);
- perfcounter->inc(l_objectcacher_cache_bytes_miss, bytes_not_in_cache);
- perfcounter->inc(l_objectcacher_cache_ops_miss);
+ if (bytes_in_cache > 0) {
+ perfcounter->inc(l_objectcacher_cache_ops_partial_hit);
+ perfcounter->inc(l_objectcacher_cache_bytes_partial_hit, bytes_in_cache);
+ } else {
+ perfcounter->inc(l_objectcacher_cache_ops_miss);
+ }
+ perfcounter->inc(l_objectcacher_cache_bytes_miss, bytes_missing);
+ perfcounter->inc(l_objectcacher_cache_bytes_rx, bytes_rx);
}
if (onfinish) {
ldout(cct, 20) << "readx defer " << rd << dendl;
}
if (perfcounter && external_call) {
perfcounter->inc(l_objectcacher_data_read, total_bytes_read);
- perfcounter->inc(l_objectcacher_cache_bytes_hit, bytes_in_cache);
+ perfcounter->inc(l_objectcacher_cache_bytes_hit, total_bytes_read);
perfcounter->inc(l_objectcacher_cache_ops_hit);
}
l_objectcacher_first = 25000,
l_objectcacher_cache_ops_hit, // ops we satisfy completely from cache
- l_objectcacher_cache_ops_miss, // ops we don't satisfy completely from cache
+ l_objectcacher_cache_ops_miss, // ops with no data in the cache
+ l_objectcacher_cache_ops_partial_hit, // ops we satisfy partially from cache
+ l_objectcacher_cache_ops_wait_cow, // ops waiting because of a copy-on-write
l_objectcacher_cache_bytes_hit, // bytes read directly from cache
- l_objectcacher_cache_bytes_miss, // bytes we couldn't read directly from cache
+ l_objectcacher_cache_bytes_partial_hit, // bytes read directly from cache for partial hits
+ l_objectcacher_cache_bytes_miss, // bytes not in the cache
+ l_objectcacher_cache_bytes_rx, // bytes waiting for pending reads
+ l_objectcacher_cache_bytes_wait_cow, // bytes waiting because of a copy-on-write
l_objectcacher_data_read, // total bytes read out
l_objectcacher_data_written, // bytes written to cache
--ref;
return ref;
}
+
+ //! Returns the size of the overlap between the BufferHead's range and the given range.
+ uint64_t overlap_size(uint64_t start, uint64_t end) {
+ uint64_t overlap_start = MAX(start, ex.start);
+ uint64_t overlap_end = MIN(end, ex.start + ex.length);
+ return overlap_end - overlap_start;
+ }
};
// ******* Object *********