summaryrefslogtreecommitdiffstats
path: root/src/crimson/os/cyan_store.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/crimson/os/cyan_store.cc')
-rw-r--r--src/crimson/os/cyan_store.cc277
1 files changed, 277 insertions, 0 deletions
diff --git a/src/crimson/os/cyan_store.cc b/src/crimson/os/cyan_store.cc
new file mode 100644
index 00000000..68ccae88
--- /dev/null
+++ b/src/crimson/os/cyan_store.cc
@@ -0,0 +1,277 @@
+#include "cyan_store.h"
+
+#include <fmt/format.h>
+
+#include "common/safe_io.h"
+
+#include "crimson/os/cyan_collection.h"
+#include "crimson/os/cyan_object.h"
+#include "crimson/os/Transaction.h"
+
+namespace {
+ seastar::logger& logger() {
+ return ceph::get_logger(ceph_subsys_filestore);
+ }
+}
+
+namespace ceph::os {
+
+using ObjectRef = boost::intrusive_ptr<Object>;
+
+CyanStore::CyanStore(const std::string& path)
+ : path{path}
+{}
+
+CyanStore::~CyanStore() = default;
+
+seastar::future<> CyanStore::mount()
+{
+ bufferlist bl;
+ string fn = path + "/collections";
+ string err;
+ if (int r = bl.read_file(fn.c_str(), &err); r < 0) {
+ throw std::runtime_error("read_file");
+ }
+
+ set<coll_t> collections;
+ auto p = bl.cbegin();
+ decode(collections, p);
+
+ for (auto& coll : collections) {
+ string fn = fmt::format("{}/{}", path, coll);
+ bufferlist cbl;
+ if (int r = cbl.read_file(fn.c_str(), &err); r < 0) {
+ throw std::runtime_error("read_file");
+ }
+ CollectionRef c{new Collection{coll}};
+ auto p = cbl.cbegin();
+ c->decode(p);
+ coll_map[coll] = c;
+ used_bytes += c->used_bytes();
+ }
+ return seastar::now();
+}
+
+seastar::future<> CyanStore::umount()
+{
+ set<coll_t> collections;
+ for (auto& [col, ch] : coll_map) {
+ collections.insert(col);
+ bufferlist bl;
+ ceph_assert(ch);
+ ch->encode(bl);
+ string fn = fmt::format("{}/{}", path, col);
+ if (int r = bl.write_file(fn.c_str()); r < 0) {
+ throw std::runtime_error("write_file");
+ }
+ }
+
+ string fn = path + "/collections";
+ bufferlist bl;
+ encode(collections, bl);
+ if (int r = bl.write_file(fn.c_str()); r < 0) {
+ throw std::runtime_error("write_file");
+ }
+ return seastar::now();
+}
+
+seastar::future<> CyanStore::mkfs(uuid_d osd_fsid)
+{
+ string fsid_str;
+ int r = read_meta("fsid", &fsid_str);
+ if (r == -ENOENT) {
+ write_meta("fsid", fmt::format("{}", osd_fsid));
+ } else if (r < 0) {
+ throw std::runtime_error("read_meta");
+ } else {
+ logger().error("{} already has fsid {}", __func__, fsid_str);
+ throw std::runtime_error("mkfs");
+ }
+
+ string fn = path + "/collections";
+ bufferlist bl;
+ set<coll_t> collections;
+ encode(collections, bl);
+ r = bl.write_file(fn.c_str());
+ if (r < 0)
+ throw std::runtime_error("write_file");
+
+ write_meta("type", "memstore");
+ return seastar::now();
+}
+
+CyanStore::CollectionRef CyanStore::create_new_collection(const coll_t& cid)
+{
+ auto c = new Collection{cid};
+ return new_coll_map[cid] = c;
+}
+
+CyanStore::CollectionRef CyanStore::open_collection(const coll_t& cid)
+{
+ auto cp = coll_map.find(cid);
+ if (cp == coll_map.end())
+ return {};
+ return cp->second;
+}
+
+std::vector<coll_t> CyanStore::list_collections()
+{
+ std::vector<coll_t> collections;
+ for (auto& coll : coll_map) {
+ collections.push_back(coll.first);
+ }
+ return collections;
+}
+
+seastar::future<bufferlist> CyanStore::read(CollectionRef c,
+ const ghobject_t& oid,
+ uint64_t offset,
+ size_t len,
+ uint32_t op_flags)
+{
+ logger().info("{} {} {} {}~{}",
+ __func__, c->cid, oid, offset, len);
+ if (!c->exists) {
+ throw std::runtime_error(fmt::format("collection does not exist: {}", c->cid));
+ }
+ ObjectRef o = c->get_object(oid);
+ if (!o) {
+ throw std::runtime_error(fmt::format("object does not exist: {}", oid));
+ }
+ if (offset >= o->get_size())
+ return seastar::make_ready_future<bufferlist>();
+ size_t l = len;
+ if (l == 0 && offset == 0) // note: len == 0 means read the entire object
+ l = o->get_size();
+ else if (offset + l > o->get_size())
+ l = o->get_size() - offset;
+ bufferlist bl;
+ if (int r = o->read(offset, l, bl); r < 0) {
+ throw std::runtime_error("read");
+ }
+ return seastar::make_ready_future<bufferlist>(std::move(bl));
+}
+
+seastar::future<CyanStore::omap_values_t>
+CyanStore::omap_get_values(CollectionRef c,
+ const ghobject_t& oid,
+ std::vector<std::string>&& keys)
+{
+ logger().info("{} {} {}",
+ __func__, c->cid, oid);
+ auto o = c->get_object(oid);
+ if (!o) {
+ throw std::runtime_error(fmt::format("object does not exist: {}", oid));
+ }
+ omap_values_t values;
+ for (auto& key : keys) {
+ if (auto found = o->omap.find(key); found != o->omap.end()) {
+ values.insert(*found);
+ }
+ }
+ return seastar::make_ready_future<omap_values_t>(std::move(values));
+}
+
+seastar::future<> CyanStore::do_transaction(CollectionRef ch,
+ Transaction&& t)
+{
+ auto i = t.begin();
+ while (i.have_op()) {
+ Transaction::Op* op = i.decode_op();
+ int r = 0;
+ switch (op->op) {
+ case Transaction::OP_NOP:
+ break;
+ case Transaction::OP_WRITE:
+ {
+ coll_t cid = i.get_cid(op->cid);
+ ghobject_t oid = i.get_oid(op->oid);
+ uint64_t off = op->off;
+ uint64_t len = op->len;
+ uint32_t fadvise_flags = i.get_fadvise_flags();
+ bufferlist bl;
+ i.decode_bl(bl);
+ r = _write(cid, oid, off, len, bl, fadvise_flags);
+ }
+ break;
+ case Transaction::OP_MKCOLL:
+ {
+ coll_t cid = i.get_cid(op->cid);
+ r = _create_collection(cid, op->split_bits);
+ }
+ break;
+ default:
+ logger().error("bad op {}", static_cast<unsigned>(op->op));
+ abort();
+ }
+ if (r < 0) {
+ abort();
+ }
+ }
+ return seastar::now();
+}
+
+int CyanStore::_write(const coll_t& cid, const ghobject_t& oid,
+ uint64_t offset, size_t len, const bufferlist& bl,
+ uint32_t fadvise_flags)
+{
+ logger().info("{} {} {} {} ~ {}",
+ __func__, cid, oid, offset, len);
+ assert(len == bl.length());
+
+ auto c = open_collection(cid);
+ if (!c)
+ return -ENOENT;
+
+ ObjectRef o = c->get_or_create_object(oid);
+ if (len > 0) {
+ const ssize_t old_size = o->get_size();
+ o->write(offset, bl);
+ used_bytes += (o->get_size() - old_size);
+ }
+
+ return 0;
+}
+
+int CyanStore::_create_collection(const coll_t& cid, int bits)
+{
+ auto result = coll_map.insert(std::make_pair(cid, CollectionRef()));
+ if (!result.second)
+ return -EEXIST;
+ auto p = new_coll_map.find(cid);
+ assert(p != new_coll_map.end());
+ result.first->second = p->second;
+ result.first->second->bits = bits;
+ new_coll_map.erase(p);
+ return 0;
+}
+
+void CyanStore::write_meta(const std::string& key,
+ const std::string& value)
+{
+ std::string v = value;
+ v += "\n";
+ if (int r = safe_write_file(path.c_str(), key.c_str(),
+ v.c_str(), v.length(), 0600);
+ r < 0) {
+ throw std::runtime_error{fmt::format("unable to write_meta({})", key)};
+ }
+}
+
+int CyanStore::read_meta(const std::string& key,
+ std::string* value)
+{
+ char buf[4096];
+ int r = safe_read_file(path.c_str(), key.c_str(),
+ buf, sizeof(buf));
+ if (r <= 0) {
+ return r;
+ }
+ // drop trailing newlines
+ while (r && isspace(buf[r-1])) {
+ --r;
+ }
+ *value = string{buf, static_cast<size_t>(r)};
+ return 0;
+}
+}