if (r == 0) {
ScrubMap::object &o = map.objects[poid];
o.size = st.st_size;
+ o.nlinks = st.st_nlink;
assert(!o.negative);
osd->store->getattrs(coll, poid, o.attrs);
o.digest_present = true;
}
+ if (poid.snap != CEPH_SNAPDIR && poid.snap != CEPH_NOSNAP) {
+ // Check snap collections
+ check_snap_collections(poid, o.attrs, &o.snapcolls);
+ }
dout(25) << "_scan_list " << poid << dendl;
} else {
dout(25) << "_scan_list " << poid << " got " << r << ", skipping" << dendl;
map<hobject_t, set<int> > &missing,
map<hobject_t, set<int> > &inconsistent,
map<hobject_t, int> &authoritative,
+ map<hobject_t, set<int> > &invalid_snapcolls,
ostream &errorstream)
{
map<hobject_t,ScrubMap::object>::const_iterator i;
set<int> cur_inconsistent;
for (j = maps.begin(); j != maps.end(); j++) {
if (j->second->objects.count(*k)) {
+ // Check snapcolls
+ if (k->snap < CEPH_MAXSNAP) {
+ if (_report_snap_collection_errors(
+ *k,
+ j->first,
+ j->second->objects[*k].attrs,
+ j->second->objects[*k].snapcolls,
+ j->second->objects[*k].nlinks,
+ errorstream)) {
+ invalid_snapcolls[*k].insert(j->first);
+ }
+ }
// Compare
stringstream ss;
if (!_compare_scrub_objects(auth->second->objects[*k],
scrubber.missing,
scrubber.inconsistent,
authoritative,
+ scrubber.inconsistent_snapcolls,
ss);
dout(2) << ss.str() << dendl;
- if (authoritative.size())
+ if (authoritative.size() || scrubber.inconsistent_snapcolls.size()) {
osd->clog.error(ss);
+ }
for (map<hobject_t, int>::iterator i = authoritative.begin();
i != authoritative.end();
bool repair = state_test(PG_STATE_REPAIR);
bool deep_scrub = state_test(PG_STATE_DEEP_SCRUB);
const char *mode = (repair ? "repair": (deep_scrub ? "deep-scrub" : "scrub"));
- if (scrubber.authoritative.size()) {
+
+ if (scrubber.authoritative.size() || scrubber.inconsistent.size()) {
stringstream ss;
+ for (map<hobject_t, set<int> >::iterator obj =
+ scrubber.inconsistent_snapcolls.begin();
+ obj != scrubber.inconsistent_snapcolls.end();
+ ++obj) {
+ for (set<int>::iterator j = obj->second.begin();
+ j != obj->second.end();
+ ++j) {
+ ++scrubber.errors;
+ ss << info.pgid << " " << mode << " " << " object " << obj->first
+ << " has inconsistent snapcolls on " << *j << std::endl;
+ }
+ }
+
ss << info.pgid << " " << mode << " " << scrubber.missing.size() << " missing, "
<< scrubber.inconsistent.size() << " inconsistent objects\n";
dout(2) << ss.str() << dendl;
// Maps from objects with erros to missing/inconsistent peers
map<hobject_t, set<int> > missing;
map<hobject_t, set<int> > inconsistent;
+ map<hobject_t, set<int> > inconsistent_snapcolls;
// Map from object with errors to good peer
map<hobject_t, pair<ScrubMap::object, int> > authoritative;
map<hobject_t, set<int> > &missing,
map<hobject_t, set<int> > &inconsistent,
map<hobject_t, int> &authoritative,
+ map<hobject_t, set<int> > &inconsistent_snapcolls,
ostream &errorstream);
void scrub();
void classic_scrub();
virtual void _scrub_finish() { }
virtual coll_t get_temp_coll() = 0;
virtual bool have_temp_coll() = 0;
+ virtual bool _report_snap_collection_errors(
+ const hobject_t &hoid,
+ int osd,
+ const map<string, bufferptr> &attrs,
+ const set<snapid_t> &snapcolls,
+ uint32_t nlinks,
+ ostream &out) { return false; };
+ virtual void check_snap_collections(
+ const hobject_t &hoid,
+ const map<string, bufferptr> &attrs,
+ set<snapid_t> *snapcolls) {};
void clear_scrub_reserved();
void scrub_reserve_replicas();
void scrub_unreserve_replicas();
}
}
+static set<snapid_t> get_expected_snap_colls(
+ const map<string, bufferptr> &attrs,
+ object_info_t *oi = 0)
+{
+ object_info_t _oi;
+ if (!oi)
+ oi = &_oi;
+
+ set<snapid_t> to_check;
+ map<string, bufferptr>::const_iterator oiiter = attrs.find(OI_ATTR);
+ if (oiiter == attrs.end())
+ return to_check;
+
+ bufferlist oiattr;
+ oiattr.push_back(oiiter->second);
+ *oi = object_info_t(oiattr);
+ if (oi->snaps.size() > 0)
+ to_check.insert(*(oi->snaps.begin()));
+ if (oi->snaps.size() > 1)
+ to_check.insert(*(oi->snaps.rbegin()));
+ return to_check;
+}
+
+bool ReplicatedPG::_report_snap_collection_errors(
+ const hobject_t &hoid,
+ int osd,
+ const map<string, bufferptr> &attrs,
+ const set<snapid_t> &snapcolls,
+ uint32_t nlinks,
+ ostream &out)
+{
+ bool errors = false;
+ set<snapid_t> to_check = get_expected_snap_colls(attrs);
+ if (to_check != snapcolls) {
+ out << info.pgid << " osd." << osd << " inconsistent snapcolls on "
+ << hoid << " found " << snapcolls << " expected " << to_check
+ << std::endl;
+ errors = true;
+ }
+ return errors;
+}
+
+void ReplicatedPG::check_snap_collections(
+ const hobject_t &hoid,
+ const map<string, bufferptr> &attrs,
+ set<snapid_t> *snapcolls)
+{
+ object_info_t oi;
+ set<snapid_t> to_check = get_expected_snap_colls(attrs, &oi);
+
+ for (set<snapid_t>::iterator i = to_check.begin(); i != to_check.end(); ++i) {
+ struct stat st;
+ int r = osd->store->stat(coll_t(info.pgid, *i), hoid, &st);
+ if (r == -ENOENT) {
+ } else if (r == 0) {
+ snapcolls->insert(*i);
+ } else {
+ assert(0);
+ }
+ }
+}
+
/*---SnapTrimmer Logging---*/
#undef dout_prefix
#define dout_prefix *_dout << pg->gen_prefix()
virtual void _scrub_clear_state();
virtual void _scrub_finish();
object_stat_collection_t scrub_cstat;
+ virtual bool _report_snap_collection_errors(
+ const hobject_t &hoid,
+ int osd,
+ const map<string, bufferptr> &attrs,
+ const set<snapid_t> &snapcolls,
+ uint32_t nlinks,
+ ostream &out);
+ virtual void check_snap_collections(
+ const hobject_t &hoid,
+ const map<string, bufferptr> &attrs,
+ set<snapid_t> *snapcolls);
virtual void _split_into(pg_t child_pgid, PG *child, unsigned split_bits);
void apply_and_flush_repops(bool requeue);