]>
git.proxmox.com Git - ceph.git/blob - ceph/src/common/hobject.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
7 #include "common/Formatter.h"
14 using ceph::bufferlist
;
15 using ceph::Formatter
;
17 static void append_escaped(const string
&in
, string
*out
)
19 for (string::const_iterator i
= in
.begin(); i
!= in
.end(); ++i
) {
23 } else if (*i
== '.') {
26 } else if (*i
== '_') {
35 set
<string
> hobject_t::get_prefixes(
41 while (len
% 4 /* nibbles */) len
++;
45 from
.insert(mask
& ~((uint32_t)(~0) << bits
));
53 for (uint32_t i
= bits
; i
< len
; ++i
) {
54 for (set
<uint32_t>::iterator j
= from
.begin();
57 to
.insert(*j
| (1U << i
));
66 uint64_t poolid(pool
);
67 t
+= snprintf(t
, sizeof(buf
), "%.*llX", 16, (long long unsigned)poolid
);
69 string
poolstr(buf
, t
- buf
);
71 for (set
<uint32_t>::iterator i
= from
.begin();
74 uint32_t revhash(hobject_t::_reverse_nibbles(*i
));
75 snprintf(buf
, sizeof(buf
), "%.*X", (int)(sizeof(revhash
))*2, revhash
);
76 ret
.insert(poolstr
+ string(buf
, len
/4));
81 string
hobject_t::to_str() const
85 char snap_with_hash
[1000];
86 char *t
= snap_with_hash
;
87 const char *end
= t
+ sizeof(snap_with_hash
);
89 uint64_t poolid(pool
);
90 t
+= snprintf(t
, end
- t
, "%.*llX", 16, (long long unsigned)poolid
);
92 uint32_t revhash(get_nibblewise_key_u32());
93 t
+= snprintf(t
, end
- t
, ".%.*X", 8, revhash
);
95 if (snap
== CEPH_NOSNAP
)
96 t
+= snprintf(t
, end
- t
, ".head");
97 else if (snap
== CEPH_SNAPDIR
)
98 t
+= snprintf(t
, end
- t
, ".snapdir");
100 t
+= snprintf(t
, end
- t
, ".%llx", (long long unsigned)snap
);
102 out
.append(snap_with_hash
, t
);
105 append_escaped(oid
.name
, &out
);
107 append_escaped(get_key(), &out
);
109 append_escaped(nspace
, &out
);
114 void hobject_t::encode(bufferlist
& bl
) const
116 ENCODE_START(4, 3, bl
);
124 ceph_assert(!max
|| (*this == hobject_t(hobject_t::get_max())));
128 void hobject_t::decode(bufferlist::const_iterator
& bl
)
130 DECODE_START_LEGACY_COMPAT_LEN(4, 3, 3, bl
);
143 // for compat with hammer, which did not handle the transition
144 // from pool -1 -> pool INT64_MIN for MIN properly. this object
145 // name looks a bit like a pgmeta object for the meta collection,
146 // but those do not ever exist (and is_pgmeta() pool >= 0).
153 ceph_assert(is_min());
156 // for compatibility with some earlier verisons which might encoded
157 // a non-canonical max object
159 *this = hobject_t::get_max();
166 void hobject_t::decode(json_spirit::Value
& v
)
168 using namespace json_spirit
;
169 Object
& o
= v
.get_obj();
170 for (Object::size_type i
=0; i
<o
.size(); i
++) {
172 if (p
.name_
== "oid")
173 oid
.name
= p
.value_
.get_str();
174 else if (p
.name_
== "key")
175 key
= p
.value_
.get_str();
176 else if (p
.name_
== "snapid")
177 snap
= p
.value_
.get_uint64();
178 else if (p
.name_
== "hash")
179 hash
= p
.value_
.get_int();
180 else if (p
.name_
== "max")
181 max
= p
.value_
.get_int();
182 else if (p
.name_
== "pool")
183 pool
= p
.value_
.get_int();
184 else if (p
.name_
== "namespace")
185 nspace
= p
.value_
.get_str();
190 void hobject_t::dump(Formatter
*f
) const
192 f
->dump_string("oid", oid
.name
);
193 f
->dump_string("key", key
);
194 f
->dump_int("snapid", snap
);
195 f
->dump_int("hash", hash
);
196 f
->dump_int("max", (int)max
);
197 f
->dump_int("pool", pool
);
198 f
->dump_string("namespace", nspace
);
201 void hobject_t::generate_test_instances(list
<hobject_t
*>& o
)
203 o
.push_back(new hobject_t
);
204 o
.push_back(new hobject_t
);
205 o
.back()->max
= true;
206 o
.push_back(new hobject_t(object_t("oname"), string(), 1, 234, -1, ""));
207 o
.push_back(new hobject_t(object_t("oname2"), string("okey"), CEPH_NOSNAP
,
209 o
.push_back(new hobject_t(object_t("oname3"), string("oname3"),
210 CEPH_SNAPDIR
, 910, 1, "n2"));
213 static void append_out_escaped(const string
&in
, string
*out
)
216 int i
= (int)(unsigned char)(c
);
218 char buf
[4] = {'%', '0'};
219 std::to_chars(buf
+ 2, buf
+ 3, i
, 16);
221 } else if (i
< 32 || i
>= 127 || i
== '%' || i
== ':' || i
== '/') {
223 std::to_chars(buf
+ 1, buf
+ 3, i
, 16);
231 static const char *decode_out_escaped(const char *in
, string
*out
)
233 while (*in
&& *in
!= ':') {
241 int v
= strtol(buf
, NULL
, 16);
251 ostream
& operator<<(ostream
& out
, const hobject_t
& o
)
253 if (o
== hobject_t())
257 out
<< o
.pool
<< ':';
261 out
<< o
.get_bitwise_key_u32(); // << '~' << o.get_hash();
267 append_out_escaped(o
.nspace
, &v
);
269 append_out_escaped(o
.get_key(), &v
);
271 append_out_escaped(o
.oid
.name
, &v
);
272 out
<< v
<< ':' << o
.snap
;
276 bool hobject_t::parse(const string
&s
)
283 *this = hobject_t::get_max();
287 const char *start
= s
.c_str();
290 int r
= sscanf(start
, "%lld:%x:", &po
, &h
);
293 for (; *start
&& *start
!= ':'; ++start
) ;
294 for (++start
; *start
&& isxdigit(*start
); ++start
) ;
299 const char *p
= decode_out_escaped(start
+ 1, &ns
);
302 p
= decode_out_escaped(p
+ 1, &k
);
305 p
= decode_out_escaped(p
+ 1, &name
);
310 unsigned long long sn
;
311 if (strncmp(start
, "head", 4) == 0) {
317 r
= sscanf(start
, "%llx", &sn
);
320 for (++start
; *start
&& isxdigit(*start
); ++start
) ;
327 set_hash(_reverse_bits(h
));
335 int cmp(const hobject_t
& l
, const hobject_t
& r
)
345 if (l
.get_bitwise_key() < r
.get_bitwise_key())
347 if (l
.get_bitwise_key() > r
.get_bitwise_key())
349 if (l
.nspace
< r
.nspace
)
351 if (l
.nspace
> r
.nspace
)
353 if (!(l
.get_key().empty() && r
.get_key().empty())) {
354 if (l
.get_effective_key() < r
.get_effective_key()) {
357 if (l
.get_effective_key() > r
.get_effective_key()) {
374 // This is compatible with decode for hobject_t prior to
376 void ghobject_t::encode(bufferlist
& bl
) const
378 // when changing this, remember to update encoded_size() too.
379 ENCODE_START(6, 3, bl
);
380 encode(hobj
.key
, bl
);
381 encode(hobj
.oid
, bl
);
382 encode(hobj
.snap
, bl
);
383 encode(hobj
.hash
, bl
);
384 encode(hobj
.max
, bl
);
385 encode(hobj
.nspace
, bl
);
386 encode(hobj
.pool
, bl
);
387 encode(generation
, bl
);
388 encode(shard_id
, bl
);
393 size_t ghobject_t::encoded_size() const
395 // this is not in order of encoding or appearance, but rather
396 // in order of known constants first, so it can be (mostly) computed
398 // - encoding header + 3 string lengths
399 size_t r
= sizeof(ceph_le32
) + 2 * sizeof(__u8
) + 3 * sizeof(__u32
);
402 r
+= sizeof(uint64_t);
405 r
+= sizeof(uint32_t);
411 r
+= sizeof(uint64_t);
414 r
+= sizeof(uint64_t);
423 r
+= hobj
.key
.size();
426 r
+= hobj
.oid
.name
.size();
429 r
+= hobj
.nspace
.size();
434 void ghobject_t::decode(bufferlist::const_iterator
& bl
)
436 DECODE_START_LEGACY_COMPAT_LEN(6, 3, 3, bl
);
438 decode(hobj
.key
, bl
);
439 decode(hobj
.oid
, bl
);
440 decode(hobj
.snap
, bl
);
441 decode(hobj
.hash
, bl
);
443 decode(hobj
.max
, bl
);
447 decode(hobj
.nspace
, bl
);
448 decode(hobj
.pool
, bl
);
449 // for compat with hammer, which did not handle the transition from
450 // pool -1 -> pool INT64_MIN for MIN properly (see hobject_t::decode()).
451 if (hobj
.pool
== -1 &&
455 hobj
.oid
.name
.empty()) {
456 hobj
.pool
= INT64_MIN
;
457 ceph_assert(hobj
.is_min());
461 decode(generation
, bl
);
462 decode(shard_id
, bl
);
464 generation
= ghobject_t::NO_GEN
;
465 shard_id
= shard_id_t::NO_SHARD
;
473 hobj
.build_hash_cache();
476 void ghobject_t::decode(json_spirit::Value
& v
)
479 using namespace json_spirit
;
480 Object
& o
= v
.get_obj();
481 for (Object::size_type i
=0; i
<o
.size(); i
++) {
483 if (p
.name_
== "generation")
484 generation
= p
.value_
.get_uint64();
485 else if (p
.name_
== "shard_id")
486 shard_id
.id
= p
.value_
.get_int();
487 else if (p
.name_
== "max")
488 max
= p
.value_
.get_int();
492 void ghobject_t::dump(Formatter
*f
) const
495 if (generation
!= NO_GEN
)
496 f
->dump_int("generation", generation
);
497 if (shard_id
!= shard_id_t::NO_SHARD
)
498 f
->dump_int("shard_id", shard_id
);
499 f
->dump_int("max", (int)max
);
502 void ghobject_t::generate_test_instances(list
<ghobject_t
*>& o
)
504 o
.push_back(new ghobject_t
);
505 o
.push_back(new ghobject_t
);
506 o
.back()->hobj
.max
= true;
507 o
.push_back(new ghobject_t(hobject_t(object_t("oname"), string(), 1, 234, -1, "")));
509 o
.push_back(new ghobject_t(hobject_t(object_t("oname2"), string("okey"), CEPH_NOSNAP
,
510 67, 0, "n1"), 1, shard_id_t(0)));
511 o
.push_back(new ghobject_t(hobject_t(object_t("oname2"), string("okey"), CEPH_NOSNAP
,
512 67, 0, "n1"), 1, shard_id_t(1)));
513 o
.push_back(new ghobject_t(hobject_t(object_t("oname2"), string("okey"), CEPH_NOSNAP
,
514 67, 0, "n1"), 1, shard_id_t(2)));
515 o
.push_back(new ghobject_t(hobject_t(object_t("oname3"), string("oname3"),
516 CEPH_SNAPDIR
, 910, 1, "n2"), 1, shard_id_t(0)));
517 o
.push_back(new ghobject_t(hobject_t(object_t("oname3"), string("oname3"),
518 CEPH_SNAPDIR
, 910, 1, "n2"), 2, shard_id_t(0)));
519 o
.push_back(new ghobject_t(hobject_t(object_t("oname3"), string("oname3"),
520 CEPH_SNAPDIR
, 910, 1, "n2"), 3, shard_id_t(0)));
521 o
.push_back(new ghobject_t(hobject_t(object_t("oname3"), string("oname3"),
522 CEPH_SNAPDIR
, 910, 1, "n2"), 3, shard_id_t(1)));
523 o
.push_back(new ghobject_t(hobject_t(object_t("oname3"), string("oname3"),
524 CEPH_SNAPDIR
, 910, 1, "n2"), 3, shard_id_t(2)));
527 ostream
& operator<<(ostream
& out
, const ghobject_t
& o
)
529 if (o
== ghobject_t())
530 return out
<< "GHMIN";
532 return out
<< "GHMAX";
533 if (o
.shard_id
!= shard_id_t::NO_SHARD
)
534 out
<< std::hex
<< o
.shard_id
<< std::dec
;
535 out
<< '#' << o
.hobj
<< '#';
536 if (o
.generation
!= ghobject_t::NO_GEN
)
537 out
<< std::hex
<< (unsigned long long)(o
.generation
) << std::dec
;
541 bool ghobject_t::parse(const string
& s
)
544 *this = ghobject_t();
548 *this = ghobject_t::get_max();
552 // look for shard# prefix
553 const char *start
= s
.c_str();
555 int sh
= shard_id_t::NO_SHARD
;
556 for (p
= start
; *p
&& isxdigit(*p
); ++p
) ;
557 if (!*p
&& *p
!= '#')
560 int r
= sscanf(s
.c_str(), "%x", &sh
);
568 // look for #generation suffix
569 long long unsigned g
= NO_GEN
;
570 const char *last
= start
+ strlen(start
) - 1;
577 sscanf(p
+ 1, "%llx", &g
);
580 string
inner(start
, p
- start
);
582 if (!h
.parse(inner
)) {
586 shard_id
= shard_id_t(sh
);
593 int cmp(const ghobject_t
& l
, const ghobject_t
& r
)
599 if (l
.shard_id
< r
.shard_id
)
601 if (l
.shard_id
> r
.shard_id
)
603 int ret
= cmp(l
.hobj
, r
.hobj
);
606 if (l
.generation
< r
.generation
)
608 if (l
.generation
> r
.generation
)