From: Piotr Dałek Date: Mon, 22 Feb 2016 12:33:43 +0000 (+0100) Subject: os/ObjectStore: implement more efficient get_encoded_bytes() X-Git-Tag: v10.1.0~213^2~5^2~1 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=325963b2c1dcdfaa5897d0f999517bfe1d8cd365;p=ceph.git os/ObjectStore: implement more efficient get_encoded_bytes() Previous version explicitly encoded entire transaction just to get its length, which resulted in encoding it twice. New method adds encoded_size() methods to ghobject_t and coll_t, which return their encoded size without explicit encoding, and in turn, reducing memory manager pressure and CPU time spent. Signed-off-by: Piotr Dałek --- diff --git a/src/common/hobject.cc b/src/common/hobject.cc index 17aecd9379a4..a58a2f015774 100644 --- a/src/common/hobject.cc +++ b/src/common/hobject.cc @@ -384,6 +384,7 @@ int cmp_bitwise(const hobject_t& l, const hobject_t& r) // version 5. void ghobject_t::encode(bufferlist& bl) const { + // when changing this, remember to update encoded_size() too. ENCODE_START(6, 3, bl); ::encode(hobj.key, bl); ::encode(hobj.oid, bl); @@ -398,6 +399,47 @@ void ghobject_t::encode(bufferlist& bl) const ENCODE_FINISH(bl); } +size_t ghobject_t::encoded_size() const +{ + // this is not in order of encoding or appearance, but rather + // in order of known constants first, so it can be (mostly) computed + // at compile time. + // - encoding header + 3 string lengths + size_t r = sizeof(ceph_le32) + 2 * sizeof(__u8) + 3 * sizeof(__u32); + + // hobj.snap + r += sizeof(uint64_t); + + // hobj.hash + r += sizeof(uint32_t); + + // hobj.max + r += sizeof(bool); + + // hobj.pool + r += sizeof(uint64_t); + + // hobj.generation + r += sizeof(uint64_t); + + // hobj.shard_id + r += sizeof(int8_t); + + // max + r += sizeof(bool); + + // hobj.key + r += hobj.key.size(); + + // hobj.oid + r += hobj.oid.name.size(); + + // hobj.nspace + r += hobj.nspace.size(); + + return r; +} + void ghobject_t::decode(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN(6, 3, 3, bl); diff --git a/src/common/hobject.h b/src/common/hobject.h index b823708441ac..0cc96fb36700 100644 --- a/src/common/hobject.h +++ b/src/common/hobject.h @@ -442,6 +442,7 @@ public: void encode(bufferlist& bl) const; void decode(bufferlist::iterator& bl); void decode(json_spirit::Value& v); + size_t encoded_size() const; void dump(Formatter *f) const; static void generate_test_instances(list& o); friend int cmp_nibblewise(const ghobject_t& l, const ghobject_t& r); diff --git a/src/os/ObjectStore.h b/src/os/ObjectStore.h index b0b952452ae8..f20280a8fafc 100644 --- a/src/os/ObjectStore.h +++ b/src/os/ObjectStore.h @@ -808,15 +808,27 @@ public: return 1 + 8 + 8 + 4 + 4 + 4 + 4 + 4 + tbl.length(); else { //layout: data_bl + op_bl + coll_index + object_index + data - //TODO: maybe we need better way to get encoded bytes; - bufferlist bl; - ::encode(coll_index, bl); - ::encode(object_index, bl); + // coll_index size, object_index size and sizeof(transaction_data) + // all here, so they may be computed at compile-time + size_t final_size = sizeof(__u32) * 2 + sizeof(data); + + // coll_index second and object_index second + final_size += (coll_index.size() + object_index.size()) * sizeof(__le32); + + // coll_index first + for (auto p = coll_index.begin(); p != coll_index.end(); ++p) { + final_size += p->first.encoded_size(); + } + + // object_index first + for (auto p = object_index.begin(); p != object_index.end(); ++p) { + final_size += p->first.encoded_size(); + } + return data_bl.length() + op_bl.length() + - bl.length() + - sizeof(data); + final_size; } } diff --git a/src/osd/osd_types.cc b/src/osd/osd_types.cc index 2d874e5fd826..903b6141f325 100644 --- a/src/osd/osd_types.cc +++ b/src/osd/osd_types.cc @@ -667,6 +667,7 @@ bool coll_t::parse(const std::string& s) void coll_t::encode(bufferlist& bl) const { + // when changing this, remember to update encoded_size() too. if (is_temp()) { // can't express this as v2... __u8 struct_v = 3; @@ -682,6 +683,33 @@ void coll_t::encode(bufferlist& bl) const } } +size_t coll_t::encoded_size() const +{ + size_t r = sizeof(__u8); + if (is_temp()) { + // v3 + r += sizeof(__u32); + if (_str) { + r += strlen(_str); + } + } else { + // v2 + // 1. type + r += sizeof(__u8); + // 2. pgid + // - encoding header + r += sizeof(ceph_le32) + 2 * sizeof(__u8); + // - pg_t + r += sizeof(__u8) + sizeof(uint64_t) + 2 * sizeof(uint32_t); + // - shard_id_t + r += sizeof(int8_t); + // 3. snapid_t + r += sizeof(uint64_t); + } + + return r; +} + void coll_t::decode(bufferlist::iterator& bl) { __u8 struct_v; diff --git a/src/osd/osd_types.h b/src/osd/osd_types.h index 84770d3e92af..74a4b1df204e 100644 --- a/src/osd/osd_types.h +++ b/src/osd/osd_types.h @@ -624,6 +624,7 @@ public: void encode(bufferlist& bl) const; void decode(bufferlist::iterator& bl); + size_t encoded_size() const; inline bool operator==(const coll_t& rhs) const { // only compare type if meta