}
return true;
}
+
+bool ObjectDesc::check_sparse(const std::map<uint64_t, uint64_t>& extents,
+ bufferlist &to_check) {
+ auto i = begin();
+ auto p = to_check.begin();
+ uint64_t pos = 0;
+ for (auto extent : extents) {
+ const uint64_t start = extent.first;
+ const uint64_t end = start + extent.second;
+ for (; pos < end; ++i, ++pos) {
+ if (i.end()) {
+ std::cout << "reached end of iterator first" << std::endl;
+ return false;
+ }
+ if (pos < start) {
+ // check the hole
+ if (*i != '\0') {
+ std::cout << "incorrect buffer at pos " << pos << std::endl;
+ return false;
+ }
+ } else {
+ // then the extent
+ if (*i != *p) {
+ std::cout << "incorrect buffer at pos " << pos << std::endl;
+ return false;
+ }
+ ++p;
+ }
+ }
+ }
+ uint64_t size = layers.empty() ? 0 :
+ most_recent_gen()->get_length(most_recent());
+ if (pos != size) {
+ std::cout << "only read " << pos << " out of size " << size << std::endl;
+ return false;
+ }
+ return true;
+}
// takes ownership of gen
void update(ContentsGenerator *gen, const ContDesc &next);
bool check(bufferlist &to_check);
+ bool check_sparse(const std::map<uint64_t, uint64_t>& extends,
+ bufferlist &to_check);
const ContDesc &most_recent();
ContentsGenerator *most_recent_gen() {
return layers.begin()->first.get();
vector<bufferlist> results;
vector<int> retvals;
+ vector<std::map<uint64_t, uint64_t>> extent_results;
+ vector<bool> is_sparse_read;
uint64_t waiting_on;
map<string, bufferlist> attrs;
balance_reads(balance_reads),
results(3),
retvals(3),
+ extent_results(3),
+ is_sparse_read(3, false),
waiting_on(0),
attrretval(0)
{}
-
+
+ void _do_read(librados::ObjectReadOperation& read_op, int index) {
+ uint64_t len = 0;
+ if (old_value.has_contents())
+ len = old_value.most_recent_gen()->get_length(old_value.most_recent());
+ if (rand() % 2) {
+ is_sparse_read[index] = false;
+ read_op.read(0,
+ len,
+ &results[index],
+ &retvals[index]);
+ } else {
+ is_sparse_read[index] = true;
+ read_op.sparse_read(0,
+ len,
+ &extent_results[index],
+ &results[index],
+ &retvals[index]);
+ }
+ }
+
void _begin()
{
context->state_lock.Lock();
if (snap >= 0) {
context->io_ctx.snap_set_read(context->snaps[snap]);
}
-
- op.read(0,
- !old_value.has_contents() ? 0 :
- old_value.most_recent_gen()->get_length(old_value.most_recent()),
- &results[0],
- &retvals[0]);
-
+ _do_read(op, 0);
for (map<string, ContDesc>::iterator i = old_value.attrs.begin();
i != old_value.attrs.end();
++i) {
// OSD's read behavior in some scenarios
for (uint32_t i = 1; i < 3; ++i) {
librados::ObjectReadOperation pipeline_op;
-
- pipeline_op.read(0,
- !old_value.has_contents() ? 0 :
- old_value.most_recent_gen()->get_length(old_value.most_recent()),
- &results[i],
- &retvals[i]);
+ _do_read(pipeline_op, i);
assert(!context->io_ctx.aio_operate(context->prefix+oid, completions[i], &pipeline_op, 0));
waiting_on++;
}
<< ", expected " << old_value.most_recent() << std::endl;
context->errors++;
}
- for (vector<bufferlist>::iterator it = results.begin();
- it != results.end(); ++it) {
- if (!old_value.check(*it)) {
- cerr << num << ": oid " << oid << " contents " << to_check << " corrupt" << std::endl;
- context->errors++;
+ for (unsigned i = 0; i < results.size(); i++) {
+ if (is_sparse_read[i]) {
+ if (!old_value.check_sparse(extent_results[i], results[i])) {
+ cerr << num << ": oid " << oid << " contents " << to_check << " corrupt" << std::endl;
+ context->errors++;
+ }
+ } else {
+ if (!old_value.check(results[i])) {
+ cerr << num << ": oid " << oid << " contents " << to_check << " corrupt" << std::endl;
+ context->errors++;
+ }
}
}
if (context->errors) assert(0);