diff --git a/src/test/osd/Object.cc b/src/test/osd/Object.cc index 37d09c3cf56..f2bc9db401f 100644 --- a/src/test/osd/Object.cc +++ b/src/test/osd/Object.cc @@ -183,3 +183,41 @@ bool ObjectDesc::check(bufferlist &to_check) { } return true; } + +bool ObjectDesc::check_sparse(const std::map& 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; +} diff --git a/src/test/osd/Object.h b/src/test/osd/Object.h index bffb397cfb6..feeefebe8dd 100644 --- a/src/test/osd/Object.h +++ b/src/test/osd/Object.h @@ -358,6 +358,8 @@ public: // takes ownership of gen void update(ContentsGenerator *gen, const ContDesc &next); bool check(bufferlist &to_check); + bool check_sparse(const std::map& extends, + bufferlist &to_check); const ContDesc &most_recent(); ContentsGenerator *most_recent_gen() { return layers.begin()->first.get(); diff --git a/src/test/osd/RadosModel.h b/src/test/osd/RadosModel.h index 9097c7a0b7c..dddaa9dec4a 100644 --- a/src/test/osd/RadosModel.h +++ b/src/test/osd/RadosModel.h @@ -992,6 +992,8 @@ public: vector results; vector retvals; + vector> extent_results; + vector is_sparse_read; uint64_t waiting_on; map attrs; @@ -1016,10 +1018,32 @@ public: 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(); @@ -1065,13 +1089,7 @@ public: 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::iterator i = old_value.attrs.begin(); i != old_value.attrs.end(); ++i) { @@ -1103,12 +1121,7 @@ public: // 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++; } @@ -1182,11 +1195,17 @@ public: << ", expected " << old_value.most_recent() << std::endl; context->errors++; } - for (vector::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);