diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 11:54:28 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 11:54:28 +0000 |
commit | e6918187568dbd01842d8d1d2c808ce16a894239 (patch) | |
tree | 64f88b554b444a49f656b6c656111a145cbbaa28 /src/cls/cas | |
parent | Initial commit. (diff) | |
download | ceph-e6918187568dbd01842d8d1d2c808ce16a894239.tar.xz ceph-e6918187568dbd01842d8d1d2c808ce16a894239.zip |
Adding upstream version 18.2.2.upstream/18.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/cls/cas')
-rw-r--r-- | src/cls/cas/cls_cas.cc | 239 | ||||
-rw-r--r-- | src/cls/cas/cls_cas_client.cc | 65 | ||||
-rw-r--r-- | src/cls/cas/cls_cas_client.h | 43 | ||||
-rw-r--r-- | src/cls/cas/cls_cas_internal.cc | 136 | ||||
-rw-r--r-- | src/cls/cas/cls_cas_internal.h | 391 | ||||
-rw-r--r-- | src/cls/cas/cls_cas_ops.h | 101 |
6 files changed, 975 insertions, 0 deletions
diff --git a/src/cls/cas/cls_cas.cc b/src/cls/cas/cls_cas.cc new file mode 100644 index 000000000..26aecd894 --- /dev/null +++ b/src/cls/cas/cls_cas.cc @@ -0,0 +1,239 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include <errno.h> + +#include "objclass/objclass.h" +#include "cls_cas_ops.h" +#include "cls_cas_internal.h" + +#include "include/compat.h" +#include "osd/osd_types.h" + +using ceph::bufferlist; +using ceph::decode; + +CLS_VER(1,0) +CLS_NAME(cas) + + +// +// helpers +// + +static int chunk_read_refcount( + cls_method_context_t hctx, + chunk_refs_t *objr) +{ + bufferlist bl; + objr->clear(); + int ret = cls_cxx_getxattr(hctx, CHUNK_REFCOUNT_ATTR, &bl); + if (ret == -ENODATA) { + return 0; + } + if (ret < 0) + return ret; + + try { + auto iter = bl.cbegin(); + decode(*objr, iter); + } catch (ceph::buffer::error& err) { + CLS_LOG(0, "ERROR: chunk_read_refcount(): failed to decode refcount entry\n"); + return -EIO; + } + + return 0; +} + +static int chunk_set_refcount( + cls_method_context_t hctx, + const struct chunk_refs_t& objr) +{ + bufferlist bl; + + encode(objr, bl); + + int ret = cls_cxx_setxattr(hctx, CHUNK_REFCOUNT_ATTR, &bl); + if (ret < 0) + return ret; + + return 0; +} + + +// +// methods +// + +static int chunk_create_or_get_ref(cls_method_context_t hctx, + bufferlist *in, bufferlist *out) +{ + auto in_iter = in->cbegin(); + + cls_cas_chunk_create_or_get_ref_op op; + try { + decode(op, in_iter); + } catch (ceph::buffer::error& err) { + CLS_LOG(1, "ERROR: failed to decode entry\n"); + return -EINVAL; + } + + chunk_refs_t objr; + int ret = chunk_read_refcount(hctx, &objr); + if (ret == -ENOENT) { + // new chunk; init refs + CLS_LOG(10, "create oid=%s\n", + op.source.oid.name.c_str()); + ret = cls_cxx_write_full(hctx, &op.data); + if (ret < 0) { + return ret; + } + objr.get(op.source); + ret = chunk_set_refcount(hctx, objr); + if (ret < 0) { + return ret; + } + } else if (ret < 0) { + return ret; + } else { + // existing chunk; inc ref + if (op.flags & cls_cas_chunk_create_or_get_ref_op::FLAG_VERIFY) { + bufferlist old; + cls_cxx_read(hctx, 0, 0, &old); + if (!old.contents_equal(op.data)) { + return -ENOMSG; + } + } + CLS_LOG(10, "inc ref oid=%s\n", + op.source.oid.name.c_str()); + + objr.get(op.source); + + ret = chunk_set_refcount(hctx, objr); + if (ret < 0) { + return ret; + } + } + return 0; +} + +static int chunk_get_ref(cls_method_context_t hctx, + bufferlist *in, bufferlist *out) +{ + auto in_iter = in->cbegin(); + + cls_cas_chunk_get_ref_op op; + try { + decode(op, in_iter); + } catch (ceph::buffer::error& err) { + CLS_LOG(1, "ERROR: failed to decode entry\n"); + return -EINVAL; + } + + chunk_refs_t objr; + int ret = chunk_read_refcount(hctx, &objr); + if (ret < 0) { + CLS_LOG(1, "ERROR: failed to read attr\n"); + return ret; + } + + // existing chunk; inc ref + CLS_LOG(10, "oid=%s\n", op.source.oid.name.c_str()); + + objr.get(op.source); + + ret = chunk_set_refcount(hctx, objr); + if (ret < 0) { + return ret; + } + return 0; +} + +static int chunk_put_ref(cls_method_context_t hctx, + bufferlist *in, bufferlist *out) +{ + auto in_iter = in->cbegin(); + + cls_cas_chunk_put_ref_op op; + try { + decode(op, in_iter); + } catch (ceph::buffer::error& err) { + CLS_LOG(1, "ERROR: failed to decode entry\n"); + return -EINVAL; + } + + chunk_refs_t objr; + int ret = chunk_read_refcount(hctx, &objr); + if (ret < 0) + return ret; + + if (!objr.put(op.source)) { + CLS_LOG(10, "oid=%s (no ref)\n", op.source.oid.name.c_str()); + return -ENOLINK; + } + + if (objr.empty()) { + CLS_LOG(10, "oid=%s (last ref)\n", op.source.oid.name.c_str()); + return cls_cxx_remove(hctx); + } + + CLS_LOG(10, "oid=%s (dec)\n", op.source.oid.name.c_str()); + ret = chunk_set_refcount(hctx, objr); + if (ret < 0) + return ret; + + return 0; +} + +static int references_chunk(cls_method_context_t hctx, + bufferlist *in, bufferlist *out) +{ + auto in_iter = in->cbegin(); + std::string fp_oid; + bufferlist indata, outdata; + try { + decode (fp_oid, in_iter); + } + catch (ceph::buffer::error& e) { + return -EINVAL; + } + CLS_LOG(10, "fp_oid: %s \n", fp_oid.c_str()); + + int ret = cls_get_manifest_ref_count(hctx, fp_oid); + if (ret) { + return ret; + } + return -ENOLINK; +} + +CLS_INIT(cas) +{ + CLS_LOG(1, "Loaded cas class!"); + + cls_handle_t h_class; + cls_method_handle_t h_chunk_create_or_get_ref; + cls_method_handle_t h_chunk_get_ref; + cls_method_handle_t h_chunk_put_ref; + cls_method_handle_t h_references_chunk; + + cls_register("cas", &h_class); + + cls_register_cxx_method(h_class, "chunk_create_or_get_ref", + CLS_METHOD_RD | CLS_METHOD_WR, + chunk_create_or_get_ref, + &h_chunk_create_or_get_ref); + cls_register_cxx_method(h_class, "chunk_get_ref", + CLS_METHOD_RD | CLS_METHOD_WR, + chunk_get_ref, + &h_chunk_get_ref); + cls_register_cxx_method(h_class, "chunk_put_ref", + CLS_METHOD_RD | CLS_METHOD_WR, + chunk_put_ref, + &h_chunk_put_ref); + cls_register_cxx_method(h_class, "references_chunk", CLS_METHOD_RD, + references_chunk, + &h_references_chunk); + + return; +} + diff --git a/src/cls/cas/cls_cas_client.cc b/src/cls/cas/cls_cas_client.cc new file mode 100644 index 000000000..085d9e52a --- /dev/null +++ b/src/cls/cas/cls_cas_client.cc @@ -0,0 +1,65 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include <errno.h> + +#include "cls/cas/cls_cas_client.h" +#include "cls/cas/cls_cas_ops.h" +#include "include/rados/librados.hpp" + +using std::set; +using std::string; + +using ceph::bufferlist; +using ceph::decode; +using ceph::encode; + +void cls_cas_chunk_create_or_get_ref( + librados::ObjectWriteOperation& op, + const hobject_t& soid, + const bufferlist& data, + bool verify) +{ + bufferlist in; + cls_cas_chunk_create_or_get_ref_op call; + call.source = soid; + if (verify) { + call.flags |= cls_cas_chunk_create_or_get_ref_op::FLAG_VERIFY; + } + call.data = data; + encode(call, in); + op.exec("cas", "chunk_create_or_get_ref", in); +} + +void cls_cas_chunk_get_ref( + librados::ObjectWriteOperation& op, + const hobject_t& soid) +{ + bufferlist in; + cls_cas_chunk_get_ref_op call; + call.source = soid; + encode(call, in); + op.exec("cas", "chunk_get_ref", in); +} + +void cls_cas_chunk_put_ref( + librados::ObjectWriteOperation& op, + const hobject_t& soid) +{ + bufferlist in; + cls_cas_chunk_put_ref_op call; + call.source = soid; + encode(call, in); + op.exec("cas", "chunk_put_ref", in); +} + +int cls_cas_references_chunk( + librados::IoCtx& io_ctx, + const string& oid, + const string& chunk_oid) +{ + bufferlist in, out; + encode(chunk_oid, in); + int r = io_ctx.exec(oid, "cas", "references_chunk", in, out); + return r; +} diff --git a/src/cls/cas/cls_cas_client.h b/src/cls/cas/cls_cas_client.h new file mode 100644 index 000000000..0abbf045b --- /dev/null +++ b/src/cls/cas/cls_cas_client.h @@ -0,0 +1,43 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#ifndef CEPH_CLS_CAS_CLIENT_H +#define CEPH_CLS_CAS_CLIENT_H + +#include "include/types.h" +#include "include/rados/librados_fwd.hpp" +#include "common/hobject.h" + +// +// basic methods +// + +/// create a chunk, or get additional reference if it already exists +void cls_cas_chunk_create_or_get_ref( + librados::ObjectWriteOperation& op, + const hobject_t& soid, + const bufferlist& data, + bool verify=false); + +/// get ref on existing chunk +void cls_cas_chunk_get_ref( + librados::ObjectWriteOperation& op, + const hobject_t& soid); + +/// drop reference on existing chunk +void cls_cas_chunk_put_ref( + librados::ObjectWriteOperation& op, + const hobject_t& soid); + + +// +// advanced (used for scrub, repair, etc.) +// + +/// check if a tiered rados object links to a chunk +int cls_cas_references_chunk( + librados::IoCtx& io_ctx, + const std::string& oid, + const std::string& chunk_oid); + +#endif diff --git a/src/cls/cas/cls_cas_internal.cc b/src/cls/cas/cls_cas_internal.cc new file mode 100644 index 000000000..891b1c311 --- /dev/null +++ b/src/cls/cas/cls_cas_internal.cc @@ -0,0 +1,136 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include "cls_cas_internal.h" + + +chunk_refs_t::chunk_refs_t(const chunk_refs_t& other) +{ + *this = other; +} + +chunk_refs_t& chunk_refs_t::operator=(const chunk_refs_t& other) +{ + // this is inefficient, but easy. + bufferlist bl; + other.encode(bl); + auto p = bl.cbegin(); + decode(p); + return *this; +} + +void chunk_refs_t::clear() +{ + // default to most precise impl + r.reset(new chunk_refs_by_object_t); +} + + +void chunk_refs_t::encode(ceph::buffer::list& bl) const +{ + bufferlist t; + _encode_r(t); + _encode_final(bl, t); +} + +void chunk_refs_t::_encode_r(ceph::bufferlist& bl) const +{ + using ceph::encode; + switch (r->get_type()) { + case TYPE_BY_OBJECT: + encode(*(chunk_refs_by_object_t*)r.get(), bl); + break; + case TYPE_BY_HASH: + encode(*(chunk_refs_by_hash_t*)r.get(), bl); + break; + case TYPE_BY_POOL: + encode(*(chunk_refs_by_pool_t*)r.get(), bl); + break; + case TYPE_COUNT: + encode(*(chunk_refs_count_t*)r.get(), bl); + break; + default: + ceph_abort("unrecognized ref type"); + } +} + +void chunk_refs_t::dynamic_encode(ceph::buffer::list& bl, size_t max) +{ + bufferlist t; + while (true) { + _encode_r(t); + // account for the additional overhead in _encode_final + if (t.length() + 8 <= max) { + break; + } + // downgrade resolution + std::unique_ptr<refs_t> n; + switch (r->get_type()) { + case TYPE_BY_OBJECT: + r.reset(new chunk_refs_by_hash_t( + static_cast<chunk_refs_by_object_t*>(r.get()))); + break; + case TYPE_BY_HASH: + if (!static_cast<chunk_refs_by_hash_t*>(r.get())->shrink()) { + r.reset(new chunk_refs_by_pool_t( + static_cast<chunk_refs_by_hash_t*>(r.get()))); + } + break; + case TYPE_BY_POOL: + r.reset(new chunk_refs_count_t(r.get())); + break; + } + t.clear(); + } + _encode_final(bl, t); +} + +void chunk_refs_t::_encode_final(bufferlist& bl, bufferlist& t) const +{ + ENCODE_START(1, 1, bl); + encode(r->get_type(), bl); + bl.claim_append(t); + ENCODE_FINISH(bl); +} + +void chunk_refs_t::decode(ceph::buffer::list::const_iterator& p) +{ + DECODE_START(1, p); + uint8_t t; + decode(t, p); + switch (t) { + case TYPE_BY_OBJECT: + { + auto n = new chunk_refs_by_object_t(); + decode(*n, p); + r.reset(n); + } + break; + case TYPE_BY_HASH: + { + auto n = new chunk_refs_by_hash_t(); + decode(*n, p); + r.reset(n); + } + break; + case TYPE_BY_POOL: + { + auto n = new chunk_refs_by_pool_t(); + decode(*n, p); + r.reset(n); + } + break; + case TYPE_COUNT: + { + auto n = new chunk_refs_count_t(); + decode(*n, p); + r.reset(n); + } + break; + default: + throw ceph::buffer::malformed_input( + std::string("unrecognized chunk ref encoding type ") + + stringify((int)t)); + } + DECODE_FINISH(p); +} diff --git a/src/cls/cas/cls_cas_internal.h b/src/cls/cas/cls_cas_internal.h new file mode 100644 index 000000000..09e7f9f1f --- /dev/null +++ b/src/cls/cas/cls_cas_internal.h @@ -0,0 +1,391 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#pragma once + +#include <string> + +#include "boost/variant.hpp" + +#include "include/stringify.h" +#include "common/Formatter.h" +#include "common/hobject.h" + +#define CHUNK_REFCOUNT_ATTR "chunk_refs" + + +// public type + +struct chunk_refs_t { + enum { + TYPE_BY_OBJECT = 1, + TYPE_BY_HASH = 2, + TYPE_BY_PARTIAL = 3, + TYPE_BY_POOL = 4, + TYPE_COUNT = 5, + }; + static const char *type_name(int t) { + switch (t) { + case TYPE_BY_OBJECT: return "by_object"; + case TYPE_BY_HASH: return "by_hash"; + case TYPE_BY_POOL: return "by_pool"; + case TYPE_COUNT: return "count"; + default: return "???"; + } + } + + struct refs_t { + virtual ~refs_t() {} + virtual uint8_t get_type() const = 0; + virtual bool empty() const = 0; + virtual uint64_t count() const = 0; + virtual void get(const hobject_t& o) = 0; + virtual bool put(const hobject_t& o) = 0; + virtual void dump(Formatter *f) const = 0; + virtual std::string describe_encoding() const { + return type_name(get_type()); + } + }; + + std::unique_ptr<refs_t> r; + + chunk_refs_t() { + clear(); + } + chunk_refs_t(const chunk_refs_t& other); + + chunk_refs_t& operator=(const chunk_refs_t&); + + void clear(); + + int get_type() const { + return r->get_type(); + } + std::string describe_encoding() const { + return r->describe_encoding(); + } + + bool empty() const { + return r->empty(); + } + uint64_t count() const { + return r->count(); + } + + void get(const hobject_t& o) { + r->get(o); + } + bool put(const hobject_t& o) { + bool ret = r->put(o); + if (r->get_type() != TYPE_BY_OBJECT && + r->count() == 0) { + clear(); // reset to full resolution, yay + } + return ret; + } + + void _encode_r(bufferlist& bl) const; + void _encode_final(bufferlist& bl, bufferlist& t) const; + void dynamic_encode(ceph::buffer::list& bl, size_t max); + void encode(ceph::buffer::list& bl) const; + void decode(ceph::buffer::list::const_iterator& p); + + void dump(Formatter *f) const { + r->dump(f); + } + static void generate_test_instances(std::list<chunk_refs_t*>& ls) { + ls.push_back(new chunk_refs_t()); + } +}; +WRITE_CLASS_ENCODER(chunk_refs_t) + + +// encoding specific types +// these are internal and should generally not be used directly + +struct chunk_refs_by_object_t : public chunk_refs_t::refs_t { + std::multiset<hobject_t> by_object; + + uint8_t get_type() const { + return chunk_refs_t::TYPE_BY_OBJECT; + } + bool empty() const override { + return by_object.empty(); + } + uint64_t count() const override { + return by_object.size(); + } + void get(const hobject_t& o) override { + by_object.insert(o); + } + bool put(const hobject_t& o) override { + auto p = by_object.find(o); + if (p == by_object.end()) { + return false; + } + by_object.erase(p); + return true; + } + void encode(bufferlist& bl) const { + ENCODE_START(1, 1, bl); + encode(by_object, bl); + ENCODE_FINISH(bl); + } + void decode(bufferlist::const_iterator& p) { + DECODE_START(1, p); + decode(by_object, p); + DECODE_FINISH(p); + } + void dump(Formatter *f) const override { + f->dump_string("type", "by_object"); + f->dump_unsigned("count", by_object.size()); + f->open_array_section("refs"); + for (auto& i : by_object) { + f->dump_object("ref", i); + } + f->close_section(); + } +}; +WRITE_CLASS_ENCODER(chunk_refs_by_object_t) + +struct chunk_refs_by_hash_t : public chunk_refs_t::refs_t { + uint64_t total = 0; + uint32_t hash_bits = 32; ///< how many bits of mask to encode + std::map<std::pair<int64_t,uint32_t>,uint64_t> by_hash; + + chunk_refs_by_hash_t() {} + chunk_refs_by_hash_t(const chunk_refs_by_object_t *o) { + total = o->count(); + for (auto& i : o->by_object) { + by_hash[std::make_pair(i.pool, i.get_hash())]++; + } + } + + std::string describe_encoding() const { + using namespace std::literals; + return "by_hash("s + stringify(hash_bits) + " bits)"; + } + + uint32_t mask() { + // with the hobject_t reverse-bitwise sort, the least significant + // hash values are actually the most significant, so preserve them + // as we lose resolution. + return 0xffffffff >> (32 - hash_bits); + } + + bool shrink() { + if (hash_bits <= 1) { + return false; + } + hash_bits--; + std::map<std::pair<int64_t,uint32_t>,uint64_t> old; + old.swap(by_hash); + auto m = mask(); + for (auto& i : old) { + by_hash[std::make_pair(i.first.first, i.first.second & m)] = i.second; + } + return true; + } + + uint8_t get_type() const { + return chunk_refs_t::TYPE_BY_HASH; + } + bool empty() const override { + return by_hash.empty(); + } + uint64_t count() const override { + return total; + } + void get(const hobject_t& o) override { + by_hash[std::make_pair(o.pool, o.get_hash() & mask())]++; + ++total; + } + bool put(const hobject_t& o) override { + auto p = by_hash.find(std::make_pair(o.pool, o.get_hash() & mask())); + if (p == by_hash.end()) { + return false; + } + if (--p->second == 0) { + by_hash.erase(p); + } + --total; + return true; + } + DENC_HELPERS + void bound_encode(size_t& p) const { + p += 6 + sizeof(uint64_t) + by_hash.size() * (10 + 10); + } + void encode(::ceph::buffer::list::contiguous_appender& p) const { + DENC_START(1, 1, p); + denc_varint(total, p); + denc_varint(hash_bits, p); + denc_varint(by_hash.size(), p); + int hash_bytes = (hash_bits + 7) / 8; + for (auto& i : by_hash) { + denc_signed_varint(i.first.first, p); + // this may write some bytes past where we move cursor too; harmless! + *(ceph_le32*)p.get_pos_add(hash_bytes) = i.first.second; + denc_varint(i.second, p); + } + DENC_FINISH(p); + } + void decode(::ceph::buffer::ptr::const_iterator& p) { + DENC_START(1, 1, p); + denc_varint(total, p); + denc_varint(hash_bits, p); + uint64_t n; + denc_varint(n, p); + int hash_bytes = (hash_bits + 7) / 8; + while (n--) { + int64_t poolid; + ceph_le32 hash; + uint64_t count; + denc_signed_varint(poolid, p); + memcpy(&hash, p.get_pos_add(hash_bytes), hash_bytes); + denc_varint(count, p); + by_hash[std::make_pair(poolid, (uint32_t)hash)] = count; + } + DENC_FINISH(p); + } + void dump(Formatter *f) const override { + f->dump_string("type", "by_hash"); + f->dump_unsigned("count", total); + f->dump_unsigned("hash_bits", hash_bits); + f->open_array_section("refs"); + for (auto& i : by_hash) { + f->open_object_section("hash"); + f->dump_int("pool", i.first.first); + f->dump_unsigned("hash", i.first.second); + f->dump_unsigned("count", i.second); + f->close_section(); + } + f->close_section(); + } +}; +WRITE_CLASS_DENC(chunk_refs_by_hash_t) + +struct chunk_refs_by_pool_t : public chunk_refs_t::refs_t { + uint64_t total = 0; + std::map<int64_t,uint64_t> by_pool; + + chunk_refs_by_pool_t() {} + chunk_refs_by_pool_t(const chunk_refs_by_hash_t *o) { + total = o->count(); + for (auto& i : o->by_hash) { + by_pool[i.first.first] += i.second; + } + } + + uint8_t get_type() const { + return chunk_refs_t::TYPE_BY_POOL; + } + bool empty() const override { + return by_pool.empty(); + } + uint64_t count() const override { + return total; + } + void get(const hobject_t& o) override { + ++by_pool[o.pool]; + ++total; + } + bool put(const hobject_t& o) override { + auto p = by_pool.find(o.pool); + if (p == by_pool.end()) { + return false; + } + --p->second; + if (p->second == 0) { + by_pool.erase(p); + } + --total; + return true; + } + void bound_encode(size_t& p) const { + p += 6 + sizeof(uint64_t) + by_pool.size() * (9 + 9); + } + DENC_HELPERS + void encode(::ceph::buffer::list::contiguous_appender& p) const { + DENC_START(1, 1, p); + denc_varint(total, p); + denc_varint(by_pool.size(), p); + for (auto& i : by_pool) { + denc_signed_varint(i.first, p); + denc_varint(i.second, p); + } + DENC_FINISH(p); + } + void decode(::ceph::buffer::ptr::const_iterator& p) { + DENC_START(1, 1, p); + denc_varint(total, p); + uint64_t n; + denc_varint(n, p); + while (n--) { + int64_t poolid; + uint64_t count; + denc_signed_varint(poolid, p); + denc_varint(count, p); + by_pool[poolid] = count; + } + DENC_FINISH(p); + } + void dump(Formatter *f) const override { + f->dump_string("type", "by_pool"); + f->dump_unsigned("count", total); + f->open_array_section("pools"); + for (auto& i : by_pool) { + f->open_object_section("pool"); + f->dump_unsigned("pool_id", i.first); + f->dump_unsigned("count", i.second); + f->close_section(); + } + f->close_section(); + } +}; +WRITE_CLASS_DENC(chunk_refs_by_pool_t) + + +struct chunk_refs_count_t : public chunk_refs_t::refs_t { + uint64_t total = 0; + + chunk_refs_count_t() {} + chunk_refs_count_t(const refs_t *old) { + total = old->count(); + } + + uint8_t get_type() const { + return chunk_refs_t::TYPE_COUNT; + } + bool empty() const override { + return total == 0; + } + uint64_t count() const override { + return total; + } + void get(const hobject_t& o) override { + ++total; + } + bool put(const hobject_t& o) override { + if (!total) { + return false; + } + --total; + return true; + } + void encode(bufferlist& bl) const { + ENCODE_START(1, 1, bl); + encode(total, bl); + ENCODE_FINISH(bl); + } + void decode(bufferlist::const_iterator& p) { + DECODE_START(1, p); + decode(total, p); + DECODE_FINISH(p); + } + void dump(Formatter *f) const override { + f->dump_string("type", "count"); + f->dump_unsigned("count", total); + } +}; +WRITE_CLASS_ENCODER(chunk_refs_count_t) + diff --git a/src/cls/cas/cls_cas_ops.h b/src/cls/cas/cls_cas_ops.h new file mode 100644 index 000000000..a79013f0e --- /dev/null +++ b/src/cls/cas/cls_cas_ops.h @@ -0,0 +1,101 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#ifndef CEPH_CLS_CAS_OPS_H +#define CEPH_CLS_CAS_OPS_H + +#include "include/types.h" +#include "common/hobject.h" +#include "common/Formatter.h" + +struct cls_cas_chunk_create_or_get_ref_op { + enum { + FLAG_VERIFY = 1, // verify content bit-for-bit if chunk already exists + }; + + hobject_t source; + uint64_t flags = 0; + bufferlist data; + + cls_cas_chunk_create_or_get_ref_op() {} + + void encode(ceph::buffer::list& bl) const { + ENCODE_START(1, 1, bl); + encode(source, bl); + encode(flags, bl); + encode(data, bl); + ENCODE_FINISH(bl); + } + + void decode(ceph::buffer::list::const_iterator& bl) { + DECODE_START(1, bl); + decode(source, bl); + decode(flags, bl); + decode(data, bl); + DECODE_FINISH(bl); + } + void dump(ceph::Formatter *f) const { + f->dump_object("source", source); + f->dump_unsigned("flags", flags); + f->dump_unsigned("data_len", data.length()); + } + static void generate_test_instances(std::list<cls_cas_chunk_create_or_get_ref_op*>& ls) { + ls.push_back(new cls_cas_chunk_create_or_get_ref_op()); + } +}; +WRITE_CLASS_ENCODER(cls_cas_chunk_create_or_get_ref_op) + + +struct cls_cas_chunk_get_ref_op { + hobject_t source; + + cls_cas_chunk_get_ref_op() {} + + void encode(ceph::buffer::list& bl) const { + ENCODE_START(1, 1, bl); + encode(source, bl); + ENCODE_FINISH(bl); + } + + void decode(ceph::buffer::list::const_iterator& bl) { + DECODE_START(1, bl); + decode(source, bl); + DECODE_FINISH(bl); + } + void dump(ceph::Formatter *f) const { + f->dump_object("source", source); + } + static void generate_test_instances(std::list<cls_cas_chunk_get_ref_op*>& ls) { + ls.push_back(new cls_cas_chunk_get_ref_op()); + } +}; +WRITE_CLASS_ENCODER(cls_cas_chunk_get_ref_op) + + +struct cls_cas_chunk_put_ref_op { + hobject_t source; + + cls_cas_chunk_put_ref_op() {} + + void encode(ceph::buffer::list& bl) const { + ENCODE_START(1, 1, bl); + encode(source, bl); + ENCODE_FINISH(bl); + } + + void decode(ceph::buffer::list::const_iterator& bl) { + DECODE_START(1, bl); + decode(source, bl); + DECODE_FINISH(bl); + } + + void dump(ceph::Formatter *f) const { + f->dump_object("source", source); + } + static void generate_test_instances(std::list<cls_cas_chunk_put_ref_op*>& ls) { + ls.push_back(new cls_cas_chunk_put_ref_op()); + } +}; +WRITE_CLASS_ENCODER(cls_cas_chunk_put_ref_op) + +#endif |