1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
5 #include "common/Formatter.h"
7 static void append_escaped(const string &in, string *out)
9 for (string::const_iterator i = in.begin(); i != in.end(); ++i) {
13 } else if (*i == '.') {
16 } else if (*i == '_') {
25 set<string> hobject_t::get_prefixes(
31 while (len % 4 /* nibbles */) len++;
35 from.insert(mask & ~((uint32_t)(~0) << bits));
43 for (uint32_t i = bits; i < len; ++i) {
44 for (set<uint32_t>::iterator j = from.begin();
47 to.insert(*j | (1U << i));
56 uint64_t poolid(pool);
57 t += snprintf(t, sizeof(buf), "%.*llX", 16, (long long unsigned)poolid);
59 string poolstr(buf, t - buf);
61 for (set<uint32_t>::iterator i = from.begin();
64 uint32_t revhash(hobject_t::_reverse_nibbles(*i));
65 snprintf(buf, sizeof(buf), "%.*X", (int)(sizeof(revhash))*2, revhash);
66 ret.insert(poolstr + string(buf, len/4));
71 string hobject_t::to_str() const
75 char snap_with_hash[1000];
76 char *t = snap_with_hash;
77 const char *end = t + sizeof(snap_with_hash);
79 uint64_t poolid(pool);
80 t += snprintf(t, end - t, "%.*llX", 16, (long long unsigned)poolid);
82 uint32_t revhash(get_nibblewise_key_u32());
83 t += snprintf(t, end - t, ".%.*X", 8, revhash);
85 if (snap == CEPH_NOSNAP)
86 t += snprintf(t, end - t, ".head");
87 else if (snap == CEPH_SNAPDIR)
88 t += snprintf(t, end - t, ".snapdir");
90 t += snprintf(t, end - t, ".%llx", (long long unsigned)snap);
92 out.append(snap_with_hash, t);
95 append_escaped(oid.name, &out);
97 append_escaped(get_key(), &out);
99 append_escaped(nspace, &out);
104 void hobject_t::encode(bufferlist& bl) const
106 ENCODE_START(4, 3, bl);
112 ::encode(nspace, bl);
114 assert(!max || (*this == hobject_t(hobject_t::get_max())));
118 void hobject_t::decode(bufferlist::iterator& bl)
120 DECODE_START_LEGACY_COMPAT_LEN(4, 3, 3, bl);
131 ::decode(nspace, bl);
133 // for compat with hammer, which did not handle the transition
134 // from pool -1 -> pool INT64_MIN for MIN properly. this object
135 // name looks a bit like a pgmeta object for the meta collection,
136 // but those do not ever exist (and is_pgmeta() pool >= 0).
146 // for compatibility with some earlier verisons which might encoded
147 // a non-canonical max object
149 *this = hobject_t::get_max();
156 void hobject_t::decode(json_spirit::Value& v)
158 using namespace json_spirit;
159 Object& o = v.get_obj();
160 for (Object::size_type i=0; i<o.size(); i++) {
162 if (p.name_ == "oid")
163 oid.name = p.value_.get_str();
164 else if (p.name_ == "key")
165 key = p.value_.get_str();
166 else if (p.name_ == "snapid")
167 snap = p.value_.get_uint64();
168 else if (p.name_ == "hash")
169 hash = p.value_.get_int();
170 else if (p.name_ == "max")
171 max = p.value_.get_int();
172 else if (p.name_ == "pool")
173 pool = p.value_.get_int();
174 else if (p.name_ == "namespace")
175 nspace = p.value_.get_str();
180 void hobject_t::dump(Formatter *f) const
182 f->dump_string("oid", oid.name);
183 f->dump_string("key", key);
184 f->dump_int("snapid", snap);
185 f->dump_int("hash", hash);
186 f->dump_int("max", (int)max);
187 f->dump_int("pool", pool);
188 f->dump_string("namespace", nspace);
191 void hobject_t::generate_test_instances(list<hobject_t*>& o)
193 o.push_back(new hobject_t);
194 o.push_back(new hobject_t);
195 o.back()->max = true;
196 o.push_back(new hobject_t(object_t("oname"), string(), 1, 234, -1, ""));
197 o.push_back(new hobject_t(object_t("oname2"), string("okey"), CEPH_NOSNAP,
199 o.push_back(new hobject_t(object_t("oname3"), string("oname3"),
200 CEPH_SNAPDIR, 910, 1, "n2"));
203 static void append_out_escaped(const string &in, string *out)
205 for (string::const_iterator i = in.begin(); i != in.end(); ++i) {
206 if (*i == '%' || *i == ':' || *i == '/' || *i < 32 || *i >= 127) {
209 snprintf(buf, sizeof(buf), "%02x", (int)(unsigned char)*i);
217 static const char *decode_out_escaped(const char *in, string *out)
219 while (*in && *in != ':') {
227 int v = strtol(buf, NULL, 16);
237 ostream& operator<<(ostream& out, const hobject_t& o)
239 if (o == hobject_t())
243 out << o.pool << ':';
247 out << o.get_bitwise_key_u32(); // << '~' << o.get_hash();
253 append_out_escaped(o.nspace, &v);
255 append_out_escaped(o.get_key(), &v);
257 append_out_escaped(o.oid.name, &v);
258 out << v << ':' << o.snap;
262 bool hobject_t::parse(const string &s)
269 *this = hobject_t::get_max();
273 const char *start = s.c_str();
276 int r = sscanf(start, "%lld:%x:", &po, &h);
279 for (; *start && *start != ':'; ++start) ;
280 for (++start; *start && isxdigit(*start); ++start) ;
285 const char *p = decode_out_escaped(start + 1, &ns);
288 p = decode_out_escaped(p + 1, &k);
291 p = decode_out_escaped(p + 1, &name);
296 unsigned long long sn;
297 if (strncmp(start, "head", 4) == 0) {
303 r = sscanf(start, "%llx", &sn);
306 for (++start; *start && isxdigit(*start); ++start) ;
313 set_hash(_reverse_bits(h));
321 int cmp(const hobject_t& l, const hobject_t& r)
331 if (l.get_bitwise_key() < r.get_bitwise_key())
333 if (l.get_bitwise_key() > r.get_bitwise_key())
335 if (l.nspace < r.nspace)
337 if (l.nspace > r.nspace)
339 if (l.get_effective_key() < r.get_effective_key())
341 if (l.get_effective_key() > r.get_effective_key())
356 // This is compatible with decode for hobject_t prior to
358 void ghobject_t::encode(bufferlist& bl) const
360 // when changing this, remember to update encoded_size() too.
361 ENCODE_START(6, 3, bl);
362 ::encode(hobj.key, bl);
363 ::encode(hobj.oid, bl);
364 ::encode(hobj.snap, bl);
365 ::encode(hobj.hash, bl);
366 ::encode(hobj.max, bl);
367 ::encode(hobj.nspace, bl);
368 ::encode(hobj.pool, bl);
369 ::encode(generation, bl);
370 ::encode(shard_id, bl);
375 size_t ghobject_t::encoded_size() const
377 // this is not in order of encoding or appearance, but rather
378 // in order of known constants first, so it can be (mostly) computed
380 // - encoding header + 3 string lengths
381 size_t r = sizeof(ceph_le32) + 2 * sizeof(__u8) + 3 * sizeof(__u32);
384 r += sizeof(uint64_t);
387 r += sizeof(uint32_t);
393 r += sizeof(uint64_t);
396 r += sizeof(uint64_t);
405 r += hobj.key.size();
408 r += hobj.oid.name.size();
411 r += hobj.nspace.size();
416 void ghobject_t::decode(bufferlist::iterator& bl)
418 DECODE_START_LEGACY_COMPAT_LEN(6, 3, 3, bl);
420 ::decode(hobj.key, bl);
421 ::decode(hobj.oid, bl);
422 ::decode(hobj.snap, bl);
423 ::decode(hobj.hash, bl);
425 ::decode(hobj.max, bl);
429 ::decode(hobj.nspace, bl);
430 ::decode(hobj.pool, bl);
431 // for compat with hammer, which did not handle the transition from
432 // pool -1 -> pool INT64_MIN for MIN properly (see hobject_t::decode()).
433 if (hobj.pool == -1 &&
437 hobj.oid.name.empty()) {
438 hobj.pool = INT64_MIN;
439 assert(hobj.is_min());
443 ::decode(generation, bl);
444 ::decode(shard_id, bl);
446 generation = ghobject_t::NO_GEN;
447 shard_id = shard_id_t::NO_SHARD;
455 hobj.build_hash_cache();
458 void ghobject_t::decode(json_spirit::Value& v)
461 using namespace json_spirit;
462 Object& o = v.get_obj();
463 for (Object::size_type i=0; i<o.size(); i++) {
465 if (p.name_ == "generation")
466 generation = p.value_.get_uint64();
467 else if (p.name_ == "shard_id")
468 shard_id.id = p.value_.get_int();
469 else if (p.name_ == "max")
470 max = p.value_.get_int();
474 void ghobject_t::dump(Formatter *f) const
477 if (generation != NO_GEN)
478 f->dump_int("generation", generation);
479 if (shard_id != shard_id_t::NO_SHARD)
480 f->dump_int("shard_id", shard_id);
481 f->dump_int("max", (int)max);
484 void ghobject_t::generate_test_instances(list<ghobject_t*>& o)
486 o.push_back(new ghobject_t);
487 o.push_back(new ghobject_t);
488 o.back()->hobj.max = true;
489 o.push_back(new ghobject_t(hobject_t(object_t("oname"), string(), 1, 234, -1, "")));
491 o.push_back(new ghobject_t(hobject_t(object_t("oname2"), string("okey"), CEPH_NOSNAP,
492 67, 0, "n1"), 1, shard_id_t(0)));
493 o.push_back(new ghobject_t(hobject_t(object_t("oname2"), string("okey"), CEPH_NOSNAP,
494 67, 0, "n1"), 1, shard_id_t(1)));
495 o.push_back(new ghobject_t(hobject_t(object_t("oname2"), string("okey"), CEPH_NOSNAP,
496 67, 0, "n1"), 1, shard_id_t(2)));
497 o.push_back(new ghobject_t(hobject_t(object_t("oname3"), string("oname3"),
498 CEPH_SNAPDIR, 910, 1, "n2"), 1, shard_id_t(0)));
499 o.push_back(new ghobject_t(hobject_t(object_t("oname3"), string("oname3"),
500 CEPH_SNAPDIR, 910, 1, "n2"), 2, shard_id_t(0)));
501 o.push_back(new ghobject_t(hobject_t(object_t("oname3"), string("oname3"),
502 CEPH_SNAPDIR, 910, 1, "n2"), 3, shard_id_t(0)));
503 o.push_back(new ghobject_t(hobject_t(object_t("oname3"), string("oname3"),
504 CEPH_SNAPDIR, 910, 1, "n2"), 3, shard_id_t(1)));
505 o.push_back(new ghobject_t(hobject_t(object_t("oname3"), string("oname3"),
506 CEPH_SNAPDIR, 910, 1, "n2"), 3, shard_id_t(2)));
509 ostream& operator<<(ostream& out, const ghobject_t& o)
511 if (o == ghobject_t())
512 return out << "GHMIN";
514 return out << "GHMAX";
515 if (o.shard_id != shard_id_t::NO_SHARD)
516 out << std::hex << o.shard_id << std::dec;
517 out << '#' << o.hobj << '#';
518 if (o.generation != ghobject_t::NO_GEN)
519 out << std::hex << (unsigned long long)(o.generation) << std::dec;
523 bool ghobject_t::parse(const string& s)
526 *this = ghobject_t();
530 *this = ghobject_t::get_max();
534 // look for shard# prefix
535 const char *start = s.c_str();
537 int sh = shard_id_t::NO_SHARD;
538 for (p = start; *p && isxdigit(*p); ++p) ;
539 if (!*p && *p != '#')
542 int r = sscanf(s.c_str(), "%x", &sh);
550 // look for #generation suffix
551 long long unsigned g = NO_GEN;
552 const char *last = start + strlen(start) - 1;
559 sscanf(p + 1, "%llx", &g);
562 string inner(start, p - start);
564 if (!h.parse(inner)) {
568 shard_id = shard_id_t(sh);
575 int cmp(const ghobject_t& l, const ghobject_t& r)
581 if (l.shard_id < r.shard_id)
583 if (l.shard_id > r.shard_id)
585 int ret = cmp(l.hobj, r.hobj);
588 if (l.generation < r.generation)
590 if (l.generation > r.generation)