CEPH_SNAPDIR, 910, 1, "n2"));
}
+static void append_out_escaped(const string &in, string *out)
+{
+ for (string::const_iterator i = in.begin(); i != in.end(); ++i) {
+ if (*i == '%' || *i == ':' || *i == '/' || *i < 32 || *i >= 127) {
+ out->push_back('%');
+ char buf[3];
+ snprintf(buf, sizeof(buf), "%02x", (int)(unsigned char)*i);
+ out->append(buf);
+ } else {
+ out->push_back(*i);
+ }
+ }
+}
+
+static const char *decode_out_escaped(const char *in, string *out)
+{
+ while (*in && *in != ':') {
+ if (*in == '%') {
+ ++in;
+ char buf[3];
+ buf[0] = *in;
+ ++in;
+ buf[1] = *in;
+ buf[2] = 0;
+ int v = strtol(buf, NULL, 16);
+ out->push_back(v);
+ } else {
+ out->push_back(*in);
+ }
+ ++in;
+ }
+ return in;
+}
+
ostream& operator<<(ostream& out, const hobject_t& o)
{
if (o == hobject_t())
return out << "MIN";
if (o.is_max())
return out << "MAX";
- out << o.pool << '/';
+ out << o.pool << ':';
out << std::hex;
out.width(8);
out.fill('0');
- out << o.get_hash();
+ out << o.get_bitwise_key_u32(); // << '~' << o.get_hash();
out.width(0);
out.fill(' ');
out << std::dec;
- if (o.nspace.length())
- out << ":" << o.nspace;
- if (o.get_key().length())
- out << "." << o.get_key();
- out << "/" << o.oid << "/" << o.snap;
+ out << ':';
+ string v;
+ append_out_escaped(o.nspace, &v);
+ v.push_back(':');
+ append_out_escaped(o.get_key(), &v);
+ v.push_back(':');
+ append_out_escaped(o.oid.name, &v);
+ out << v << ':' << o.snap;
return out;
}
+bool hobject_t::parse(const string &s)
+{
+ if (s == "MIN") {
+ *this = hobject_t();
+ return true;
+ }
+ if (s == "MAX") {
+ *this = hobject_t::get_max();
+ return true;
+ }
+
+ const char *start = s.c_str();
+ long long po;
+ unsigned h;
+ int r = sscanf(start, "%lld:%x:", &po, &h);
+ if (r != 2)
+ return false;
+ for (; *start && *start != ':'; ++start) ;
+ for (++start; *start && isxdigit(*start); ++start) ;
+ if (*start != ':')
+ return false;
+
+ string ns, k, name;
+ const char *p = decode_out_escaped(start + 1, &ns);
+ if (*p != ':')
+ return false;
+ p = decode_out_escaped(p + 1, &k);
+ if (*p != ':')
+ return false;
+ p = decode_out_escaped(p + 1, &name);
+ if (*p != ':')
+ return false;
+ start = p + 1;
+
+ unsigned long long sn;
+ if (strncmp(start, "head", 4) == 0) {
+ sn = CEPH_NOSNAP;
+ start += 4;
+ if (*start != 0)
+ return false;
+ } else {
+ r = sscanf(start, "%llx", &sn);
+ if (r != 1)
+ return false;
+ for (++start; *start && isxdigit(*start); ++start) ;
+ if (*start)
+ return false;
+ }
+
+ max = false;
+ pool = po;
+ set_hash(_reverse_bits(h));
+ nspace = ns;
+ oid.name = name;
+ set_key(k);
+ snap = sn;
+ return true;
+}
+
int cmp_nibblewise(const hobject_t& l, const hobject_t& r)
{
if (l.max < r.max)
if (o.is_max())
return out << "GHMAX";
if (o.shard_id != shard_id_t::NO_SHARD)
- out << std::hex << o.shard_id << std::dec << ":";
- out << o.hobj;
- if (o.generation != ghobject_t::NO_GEN) {
- out << "/" << std::hex << (unsigned)(o.generation) << std::dec;
- }
+ out << std::hex << o.shard_id << std::dec;
+ out << '@' << o.hobj << '@';
+ if (o.generation != ghobject_t::NO_GEN)
+ out << std::hex << (unsigned long long)(o.generation) << std::dec;
return out;
}
+bool ghobject_t::parse(const string& s)
+{
+ if (s == "GHMIN") {
+ *this = ghobject_t();
+ return true;
+ }
+ if (s == "GHMAX") {
+ *this = ghobject_t::get_max();
+ return true;
+ }
+
+ // look for shard@ prefix
+ const char *start = s.c_str();
+ const char *p;
+ int sh = shard_id_t::NO_SHARD;
+ for (p = start; *p && isxdigit(*p); ++p) ;
+ if (!*p && *p != '@')
+ return false;
+ if (p > start) {
+ int r = sscanf(s.c_str(), "%x", &sh);
+ if (r < 1)
+ return false;
+ start = p + 1;
+ } else {
+ ++start;
+ }
+
+ // look for @generation suffix
+ long long unsigned g = NO_GEN;
+ const char *last = start + strlen(start) - 1;
+ p = last;
+ while (isxdigit(*p))
+ p--;
+ if (*p != '@')
+ return false;
+ if (p < last) {
+ sscanf(p + 1, "%llx", &g);
+ }
+
+ string inner(start, p - start);
+ hobject_t h;
+ if (!h.parse(inner)) {
+ return false;
+ }
+
+ shard_id = shard_id_t(sh);
+ hobj = h;
+ generation = g;
+ max = false;
+ return true;
+}
+
int cmp_nibblewise(const ghobject_t& l, const ghobject_t& r)
{
if (l.max < r.max)
return nspace;
}
+ bool parse(const string& s);
+
void encode(bufferlist& bl) const;
void decode(bufferlist::iterator& bl);
void decode(json_spirit::Value& v);
shard_id = s;
}
+ bool parse(const string& s);
+
// maximum sorted value.
static ghobject_t get_max() {
ghobject_t h;
kill_daemons $dir || return 1
declare -a err_strings
- err_strings[0]="log_channel[(]cluster[)] log [[]ERR[]] : scrub [0-9]*[.]0 [0-9]*/2acecc8b/obj10/1 is missing in clone_overlap"
- err_strings[1]="log_channel[(]cluster[)] log [[]ERR[]] : scrub [0-9]*[.]0 [0-9]*/666934a3/obj5/7 no '_' attr"
- err_strings[2]="log_channel[(]cluster[)] log [[]ERR[]] : scrub [0-9]*[.]0 [0-9]*/666934a3/obj5/7 is an unexpected clone"
- err_strings[3]="log_channel[(]cluster[)] log [[]ERR[]] : scrub [0-9]*[.]0 [0-9]*/666934a3/obj5/4 on disk size [(]4608[)] does not match object info size [(]512[)] adjusted for ondisk to [(]512[)]"
- err_strings[4]="log_channel[(]cluster[)] log [[]ERR[]] : scrub [0-9]*[.]0 [0-9]*/666934a3/obj5/head expected clone [0-9]*/666934a3/obj5/2"
- err_strings[5]="log_channel[(]cluster[)] log [[]ERR[]] : scrub [0-9]*[.]0 [0-9]*/666934a3/obj5/head expected clone [0-9]*/666934a3/obj5/1"
- err_strings[6]="log_channel[(]cluster[)] log [[]INF[]] : scrub [0-9]*[.]0 [0-9]*/666934a3/obj5/head 2 missing clone[(]s[)]"
- err_strings[7]="log_channel[(]cluster[)] log [[]ERR[]] : scrub [0-9]*[.]0 [0-9]*/d3a9faf5/obj12/head snapset.head_exists=false, but head exists"
- err_strings[8]="log_channel[(]cluster[)] log [[]ERR[]] : scrub [0-9]*[.]0 [0-9]*/8df7eaa5/obj8/head snaps.seq not set"
- err_strings[9]="log_channel[(]cluster[)] log [[]ERR[]] : scrub [0-9]*[.]0 [0-9]*/5c889059/obj7/head snapset.head_exists=false, but head exists"
- err_strings[10]="log_channel[(]cluster[)] log [[]ERR[]] : scrub [0-9]*[.]0 [0-9]*/5c889059/obj7/1 is an unexpected clone"
- err_strings[11]="log_channel[(]cluster[)] log [[]ERR[]] : scrub [0-9]*[.]0 [0-9]*/61f68bb1/obj3/head on disk size [(]3840[)] does not match object info size [(]768[)] adjusted for ondisk to [(]768[)]"
- err_strings[12]="log_channel[(]cluster[)] log [[]ERR[]] : scrub [0-9]*[.]0 [0-9]*/83425cc4/obj6/1 is an unexpected clone"
- err_strings[13]="log_channel[(]cluster[)] log [[]ERR[]] : scrub [0-9]*[.]0 [0-9]*/3f1ee208/obj2/snapdir no 'snapset' attr"
- err_strings[14]="log_channel[(]cluster[)] log [[]INF[]] : scrub [0-9]*[.]0 [0-9]*/3f1ee208/obj2/7 clone ignored due to missing snapset"
- err_strings[15]="log_channel[(]cluster[)] log [[]INF[]] : scrub [0-9]*[.]0 [0-9]*/3f1ee208/obj2/4 clone ignored due to missing snapset"
- err_strings[16]="log_channel[(]cluster[)] log [[]ERR[]] : scrub [0-9]*[.]0 [0-9]*/a8759770/obj4/snapdir expected clone [0-9]*/a8759770/obj4/7"
- err_strings[17]="log_channel[(]cluster[)] log [[]INF[]] : scrub [0-9]*[.]0 [0-9]*/a8759770/obj4/snapdir 1 missing clone[(]s[)]"
- err_strings[18]="log_channel[(]cluster[)] log [[]ERR[]] : scrub [0-9]*[.]0 [0-9]*/6cf8deff/obj1/1 is an unexpected clone"
- err_strings[19]="log_channel[(]cluster[)] log [[]ERR[]] : scrub [0-9]*[.]0 [0-9]*/e478ac7f/obj9/1 is missing in clone_size"
- err_strings[20]="log_channel[(]cluster[)] log [[]ERR[]] : scrub [0-9]*[.]0 [0-9]*/29547577/obj11/1 is an unexpected clone"
- err_strings[21]="log_channel[(]cluster[)] log [[]ERR[]] : scrub [0-9]*[.]0 [0-9]*/94122507/obj14/1 size 1032 != clone_size 1033"
+ err_strings[0]="log_channel[(]cluster[)] log [[]ERR[]] : scrub [0-9]*[.]0 .*::obj10:.* is missing in clone_overlap"
+ err_strings[1]="log_channel[(]cluster[)] log [[]ERR[]] : scrub [0-9]*[.]0 .*::obj5:7 no '_' attr"
+ err_strings[2]="log_channel[(]cluster[)] log [[]ERR[]] : scrub [0-9]*[.]0 .*::obj5:7 is an unexpected clone"
+ err_strings[3]="log_channel[(]cluster[)] log [[]ERR[]] : scrub [0-9]*[.]0 .*::obj5:4 on disk size [(]4608[)] does not match object info size [(]512[)] adjusted for ondisk to [(]512[)]"
+ err_strings[4]="log_channel[(]cluster[)] log [[]ERR[]] : scrub [0-9]*[.]0 .*:::obj5:head expected clone .*:::obj5:2"
+ err_strings[5]="log_channel[(]cluster[)] log [[]ERR[]] : scrub [0-9]*[.]0 .*:::obj5:head expected clone .*:::obj5:1"
+ err_strings[6]="log_channel[(]cluster[)] log [[]INF[]] : scrub [0-9]*[.]0 .*:::obj5:head 2 missing clone[(]s[)]"
+ err_strings[7]="log_channel[(]cluster[)] log [[]ERR[]] : scrub [0-9]*[.]0 .*:::obj12:head snapset.head_exists=false, but head exists"
+ err_strings[8]="log_channel[(]cluster[)] log [[]ERR[]] : scrub [0-9]*[.]0 .*:::obj8:head snaps.seq not set"
+ err_strings[9]="log_channel[(]cluster[)] log [[]ERR[]] : scrub [0-9]*[.]0 .*:::obj7:head snapset.head_exists=false, but head exists"
+ err_strings[10]="log_channel[(]cluster[)] log [[]ERR[]] : scrub [0-9]*[.]0 .*:::obj7:1 is an unexpected clone"
+ err_strings[11]="log_channel[(]cluster[)] log [[]ERR[]] : scrub [0-9]*[.]0 .*:::obj3:head on disk size [(]3840[)] does not match object info size [(]768[)] adjusted for ondisk to [(]768[)]"
+ err_strings[12]="log_channel[(]cluster[)] log [[]ERR[]] : scrub [0-9]*[.]0 .*:::obj6:1 is an unexpected clone"
+ err_strings[13]="log_channel[(]cluster[)] log [[]ERR[]] : scrub [0-9]*[.]0 .*:::obj2:snapdir no 'snapset' attr"
+ err_strings[14]="log_channel[(]cluster[)] log [[]INF[]] : scrub [0-9]*[.]0 .*:::obj2:7 clone ignored due to missing snapset"
+ err_strings[15]="log_channel[(]cluster[)] log [[]INF[]] : scrub [0-9]*[.]0 .*:::obj2:4 clone ignored due to missing snapset"
+ err_strings[16]="log_channel[(]cluster[)] log [[]ERR[]] : scrub [0-9]*[.]0 .*:::obj4:snapdir expected clone .*:::obj4:7"
+ err_strings[17]="log_channel[(]cluster[)] log [[]INF[]] : scrub [0-9]*[.]0 .*:::obj4:snapdir 1 missing clone[(]s[)]"
+ err_strings[18]="log_channel[(]cluster[)] log [[]ERR[]] : scrub [0-9]*[.]0 .*:::obj1:1 is an unexpected clone"
+ err_strings[19]="log_channel[(]cluster[)] log [[]ERR[]] : scrub [0-9]*[.]0 .*:::obj9:1 is missing in clone_size"
+ err_strings[20]="log_channel[(]cluster[)] log [[]ERR[]] : scrub [0-9]*[.]0 .*:::obj11:1 is an unexpected clone"
+ err_strings[21]="log_channel[(]cluster[)] log [[]ERR[]] : scrub [0-9]*[.]0 .*:::obj14:1 size 1032 != clone_size 1033"
err_strings[22]="log_channel[(]cluster[)] log [[]ERR[]] : [0-9]*[.]0 scrub 19 errors"
for i in `seq 0 ${#err_strings[@]}`
ASSERT_NE(left.c_str(), middle.c_str());
}
+TEST(hobject_t, parse) {
+ const char *v[] = {
+ "MIN",
+ "MAX",
+ "-1:60c2fa6d:::inc_osdmap.1:0",
+ "-1:60c2fa6d:::inc_osdmap.1:333",
+ "0:00000000::::head",
+ "1:00000000:nspace:key:obj:head",
+ "-40:00000000:nspace::obj:head",
+ "20:00000000::key:obj:head",
+ "20:00000000:::o%fdj:head",
+ "20:00000000:::o%02fdj:head",
+ "20:00000000:::_zero_%00_:head",
+ NULL
+ };
+
+ for (unsigned i=0; v[i]; ++i) {
+ hobject_t o;
+ bool b = o.parse(v[i]);
+ if (!b) {
+ cout << "failed to parse " << v[i] << std::endl;
+ ASSERT_TRUE(false);
+ }
+ string s = stringify(o);
+ if (s != v[i]) {
+ cout << v[i] << " -> " << o << " -> " << s << std::endl;
+ ASSERT_EQ(s, string(v[i]));
+ }
+ }
+}
+
TEST(ghobject_t, cmp) {
ghobject_t min;
ghobject_t sep;
ASSERT_TRUE(cmp_bitwise(o, sep) > 0);
}
+TEST(ghobject_t, parse) {
+ const char *v[] = {
+ "GHMIN",
+ "GHMAX",
+ "13@0:00000000::::head@",
+ "13@0:00000000::::head@deadbeef",
+ "@-1:60c2fa6d:::inc_osdmap.1:333@deadbeef",
+ "@-1:60c2fa6d:::inc%02osdmap.1:333@deadbeef",
+ "@-1:60c2fa6d:::inc_osdmap.1:333@",
+ "1@MIN@deadbeefff",
+ "1@MAX@",
+ "@MAX@123",
+ "@-40:00000000:nspace::obj:head@",
+ NULL
+ };
+
+ for (unsigned i=0; v[i]; ++i) {
+ ghobject_t o;
+ bool b = o.parse(v[i]);
+ if (!b) {
+ cout << "failed to parse " << v[i] << std::endl;
+ ASSERT_TRUE(false);
+ }
+ string s = stringify(o);
+ if (s != v[i]) {
+ cout << v[i] << " -> " << o << " -> " << s << std::endl;
+ ASSERT_EQ(s, string(v[i]));
+ }
+ }
+}
+
TEST(pool_opts_t, invalid_opt) {
EXPECT_FALSE(pool_opts_t::is_opt_name("INVALID_OPT"));
EXPECT_DEATH(pool_opts_t::get_opt_desc("INVALID_OPT"), "");