}
}
-int DBObjectMap::check(std::ostream &out, bool repair)
+int DBObjectMap::check(std::ostream &out, bool repair, bool force)
{
- int errors = 0;
+ int errors = 0, comp_errors = 0;
bool repaired = false;
map<uint64_t, uint64_t> parent_to_num_children;
map<uint64_t, uint64_t> parent_to_actual_num_children;
if (header.seq != 0)
parent_to_actual_num_children[header.seq] = header.num_children;
- // Check complete table
- bool complete_error = false;
- boost::optional<string> prev;
- KeyValueDB::Iterator complete_iter = db->get_iterator(USER_PREFIX + header_key(header.seq) + COMPLETE_PREFIX);
- for (complete_iter->seek_to_first(); complete_iter->valid();
- complete_iter->next()) {
- if (prev && prev >= complete_iter->key()) {
- out << "Bad complete for " << header.oid << std::endl;
- complete_error = true;
- break;
- }
- prev = string(complete_iter->value().c_str(), complete_iter->value().length() - 1);
- }
- if (complete_error) {
- out << "Complete mapping for " << header.seq << " :" << std::endl;
- for (complete_iter->seek_to_first(); complete_iter->valid();
- complete_iter->next()) {
- out << complete_iter->key() << " -> " << string(complete_iter->value().c_str(), complete_iter->value().length() - 1) << std::endl;
- }
- if (repair) {
- repaired = true;
- KeyValueDB::Transaction t = db->get_transaction();
- t->rmkeys_by_prefix(USER_PREFIX + header_key(header.seq) + COMPLETE_PREFIX);
- db->submit_transaction(t);
- out << "Cleared complete mapping to repair" << std::endl;
- } else {
- errors++; // Only count when not repaired
- }
+ if (state.v == 2 || force) {
+ // Check complete table
+ bool complete_error = false;
+ boost::optional<string> prev;
+ KeyValueDB::Iterator complete_iter = db->get_iterator(USER_PREFIX + header_key(header.seq) + COMPLETE_PREFIX);
+ for (complete_iter->seek_to_first(); complete_iter->valid();
+ complete_iter->next()) {
+ if (prev && prev >= complete_iter->key()) {
+ out << "Bad complete for " << header.oid << std::endl;
+ complete_error = true;
+ break;
+ }
+ prev = string(complete_iter->value().c_str(), complete_iter->value().length() - 1);
+ }
+ if (complete_error) {
+ out << "Complete mapping for " << header.seq << " :" << std::endl;
+ for (complete_iter->seek_to_first(); complete_iter->valid();
+ complete_iter->next()) {
+ out << complete_iter->key() << " -> " << string(complete_iter->value().c_str(), complete_iter->value().length() - 1) << std::endl;
+ }
+ if (repair) {
+ repaired = true;
+ KeyValueDB::Transaction t = db->get_transaction();
+ t->rmkeys_by_prefix(USER_PREFIX + header_key(header.seq) + COMPLETE_PREFIX);
+ db->submit_transaction(t);
+ out << "Cleared complete mapping to repair" << std::endl;
+ } else {
+ errors++; // Only count when not repaired
+ comp_errors++; // Track errors here for version update
+ }
+ }
}
if (header.parent == 0)
}
parent_to_actual_num_children.erase(i->first);
}
+
+ // Only advance the version from 2 to 3 here
+ // Mark as legacy because there are still older structures
+ // we don't update. The value of legacy is only used
+ // for internal assertions.
+ if (comp_errors == 0 && state.v == 2 && repair) {
+ state.v = 3;
+ state.legacy = true;
+ set_state();
+ }
+
if (errors == 0 && repaired)
return -1;
return errors;
return db->submit_transaction(t);
}
- assert(state.v < 3);
+ assert(state.legacy);
{
// We only get here for legacy (v2) stores
const ghobject_t &target,
const SequencerPosition *spos)
{
- state.v = 2;
+ state.legacy = true;
if (oid == target)
return 0;
Mutex::Locker l(header_lock);
KeyValueDB::Transaction t = db->get_transaction();
write_state(t);
- db->submit_transaction_sync(t);
+ int ret = db->submit_transaction_sync(t);
+ assert(ret == 0);
dout(1) << __func__ << " done" << dendl;
return;
}
state.decode(bliter);
} else {
// New store
- // Version 3 means that complete regions never used
- state.v = 3;
+ state.v = State::CUR_VERSION;
state.seq = 1;
+ state.legacy = false;
}
return 0;
}
dout(20) << "clear_header: clearing seq " << header->seq << dendl;
t->rmkeys_by_prefix(user_prefix(header));
t->rmkeys_by_prefix(sys_prefix(header));
- if (state.v < 3)
+ if (state.legacy)
t->rmkeys_by_prefix(complete_prefix(header)); // Needed when header.parent != 0
t->rmkeys_by_prefix(xattr_prefix(header));
set<string> keys;
int upgrade_to_v2();
/// Consistency check, debug, there must be no parallel writes
- int check(std::ostream &out, bool repair = false) override;
+ int check(std::ostream &out, bool repair = false, bool force = false) override;
/// Ensure that all previous operations are durable
int sync(const ghobject_t *oid=0, const SequencerPosition *spos=0) override;
/// persistent state for store @see generate_header
struct State {
+ static const __u8 CUR_VERSION = 3;
__u8 v;
uint64_t seq;
- State() : v(0), seq(1) {}
- explicit State(uint64_t seq) : v(0), seq(seq) {}
+ // legacy is false when complete regions never used
+ bool legacy;
+ State() : v(0), seq(1), legacy(false) {}
+ explicit State(uint64_t seq) : v(0), seq(seq), legacy(false) {}
void encode(bufferlist &bl) const {
- ENCODE_START(2, 1, bl);
+ ENCODE_START(3, 1, bl);
::encode(v, bl);
::encode(seq, bl);
+ ::encode(legacy, bl);
ENCODE_FINISH(bl);
}
void decode(bufferlist::iterator &bl) {
- DECODE_START(2, bl);
+ DECODE_START(3, bl);
if (struct_v >= 2)
::decode(v, bl);
else
v = 0;
::decode(seq, bl);
+ if (struct_v >= 3)
+ ::decode(legacy, bl);
+ else
+ legacy = false;
DECODE_FINISH(bl);
}
void dump(Formatter *f) const {
+ f->dump_unsigned("v", v);
f->dump_unsigned("seq", seq);
+ f->dump_bool("legacy", legacy);
}
static void generate_test_instances(list<State*> &o) {
omap.get_state();
std::cout << "Version: " << (int)omap.state.v << std::endl;
std::cout << "Seq: " << omap.state.seq << std::endl;
+ std::cout << "legacy: " << (omap.state.legacy ? "true" : "false") << std::endl;
if (cmd == "dump-raw-keys") {
KeyValueDB::WholeSpaceIterator i = store->get_iterator();
} else if (cmd == "check" || cmd == "repair") {
ostringstream ss;
bool repair = (cmd == "repair");
- r = omap.check(ss, repair);
+ r = omap.check(ss, repair, true);
if (r) {
std::cerr << ss.str() << std::endl;
if (r > 0) {
return 0;
} else if (cmd == "resetv2") {
omap.state.v = 2;
+ omap.state.legacy = false;
omap.set_state();
} else {
std::cerr << "Did not recognize command " << cmd << std::endl;