summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSamuel Just <sam.just@inktank.com>2012-11-28 15:10:43 -0800
committerSamuel Just <sam.just@inktank.com>2012-11-29 13:57:55 -0800
commit5c8cbd28207195b094799a7bdbad0019669682a8 (patch)
treea668c63b1d719c36494686d9f8120a435b1db749
parent206f39e3b8a6d4e566feb841f1fea475857fae17 (diff)
downloadceph-5c8cbd28207195b094799a7bdbad0019669682a8.tar.gz
PG: scrubber.end should be exactly a boundary
Let scrubber.end be (foo, HEAD, 10) where the oid is foo , HEAD is the snap, and 10 is the hash and scrubber.begin similarly be (bar, 5, 1). After choosing to scan [(bar, 5, 1), (foo, HEAD, 10)), we block writes on that interval. 1) A write might then come in for foo (which isn't blocked) which creates a new snap (foo, 400, 10) which happens to fall in the interval. This will result in a crash in _scrub() when it attempts to compare clones since it will get (foo, 400, 10) but not the head object (foo, HEAD, 10). 2) Alternately, the write from 1) has already happened. When we scan the log, we find 34'10 and 34'11 are the clone operation creating (foo, 400, 10) and the modify on (foo, HEAD, 10) respectively. Both primary and replica will wait for last_update_applied to be 34'10 before scanning, but last_update_applied will in fact skip to 34'11 since 34'10 and 34'11 happened in the same transaction. This can result in IO hanging on the scrubber interval. Instead, we ensure that scrubber.end is exactly a hash boundary (min hobject_t a with the specified hash). No such object can exist since we don't create objects with empty oids, so no writes can occur on that object. Signed-off-by: Samuel Just <sam.just@inktank.com>
-rw-r--r--src/os/hobject.h9
-rw-r--r--src/osd/PG.cc2
2 files changed, 10 insertions, 1 deletions
diff --git a/src/os/hobject.h b/src/os/hobject.h
index 00097f47157..d75ae8570c4 100644
--- a/src/os/hobject.h
+++ b/src/os/hobject.h
@@ -59,6 +59,15 @@ public:
pool(pool),
key(soid.oid.name == key ? string() : key) {}
+ /// @return min hobject_t ret s.t. ret.hash == this->hash
+ hobject_t get_boundary() const {
+ if (is_max())
+ return *this;
+ hobject_t ret;
+ ret.hash = hash;
+ return ret;
+ }
+
/* Do not use when a particular hash function is needed */
explicit hobject_t(const sobject_t &o) :
oid(o.oid), snap(o.snap), max(false), pool(-1) {
diff --git a/src/osd/PG.cc b/src/osd/PG.cc
index 2bc5d127c9c..b81bfed36f4 100644
--- a/src/osd/PG.cc
+++ b/src/osd/PG.cc
@@ -3694,7 +3694,7 @@ void PG::chunky_scrub() {
// search backward from the end looking for a boundary
objects.push_back(scrubber.end);
while (!boundary_found && objects.size() > 1) {
- hobject_t end = objects.back();
+ hobject_t end = objects.back().get_boundary();
objects.pop_back();
if (objects.back().get_filestore_key() != end.get_filestore_key()) {