summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRoman Smrž <roman.smrz@seznam.cz>2020-06-07 22:23:40 +0200
committerRoman Smrž <roman.smrz@seznam.cz>2020-07-20 21:39:02 +0200
commit8ac21c24e49bc3702c55d1c796f969f1d1f6128b (patch)
tree6a24dcad00857212bd5584807ddd794de65ee01f /src
parent692e64613c45d6cfb9444931084b4a04965e826e (diff)
Storage: typed heads
Diffstat (limited to 'src')
-rw-r--r--src/storage.cpp238
-rw-r--r--src/storage.h25
2 files changed, 252 insertions, 11 deletions
diff --git a/src/storage.cpp b/src/storage.cpp
index 16662df..b5bff8c 100644
--- a/src/storage.cpp
+++ b/src/storage.cpp
@@ -18,6 +18,7 @@ using namespace erebos;
using std::array;
using std::copy;
+using std::get;
using std::holds_alternative;
using std::ifstream;
using std::is_same_v;
@@ -30,7 +31,6 @@ using std::runtime_error;
using std::shared_ptr;
using std::string;
using std::to_string;
-using std::tuple;
FilesystemStorage::FilesystemStorage(const fs::path & path):
root(path)
@@ -125,16 +125,7 @@ void FilesystemStorage::storeBytes(const Digest & digest, const vector<uint8_t>
auto lock = path;
lock += ".lock";
- fs::create_directories(path.parent_path());
-
- // No way to use open exclusively in c++ stdlib
- FILE *f = nullptr;
- for (int i = 0; i < 10; i++) {
- f = fopen(lock.c_str(), "wbxe");
- if (f || errno != EEXIST)
- break;
- std::this_thread::sleep_for(std::chrono::milliseconds(100));
- }
+ FILE * f = openLockFile(lock);
if (fs::exists(path)) {
if (f) {
fclose(f);
@@ -171,6 +162,81 @@ void FilesystemStorage::storeBytes(const Digest & digest, const vector<uint8_t>
fs::rename(lock, path);
}
+optional<Digest> FilesystemStorage::headRef(UUID type, UUID id) const
+{
+ ifstream fin(headPath(type, id));
+ if (!fin)
+ return nullopt;
+
+ string sdgst;
+ fin >> sdgst;
+ return Digest(sdgst);
+}
+
+vector<tuple<UUID, Digest>> FilesystemStorage::headRefs(UUID type) const
+{
+ vector<tuple<UUID, Digest>> res;
+ string stype(type);
+ fs::path ptype(stype.begin(), stype.end());
+ try {
+ for (const auto & p : fs::directory_iterator(root/"heads"/ptype))
+ if (auto u = UUID::fromString(p.path().filename())) {
+ ifstream fin(p.path());
+ if (fin) {
+ string sdgst;
+ fin >> sdgst;
+ res.emplace_back(*u, Digest(sdgst));
+ }
+ }
+ } catch (const fs::filesystem_error & e) {
+ if (e.code() == std::errc::no_such_file_or_directory)
+ return {};
+ throw e;
+ }
+ return res;
+}
+
+UUID FilesystemStorage::storeHead(UUID type, const Digest & dgst)
+{
+ auto id = UUID::generate();
+ auto path = headPath(type, id);
+ fs::create_directories(path.parent_path());
+ ofstream fout(path);
+ if (!fout)
+ throw runtime_error("failed to open head file");
+
+ fout << string(dgst) << '\n';
+ return id;
+}
+
+bool FilesystemStorage::replaceHead(UUID type, UUID id, const Digest & old, const Digest & dgst)
+{
+ auto path = headPath(type, id);
+ auto lock = path;
+ lock += ".lock";
+ FILE * f = openLockFile(lock);
+ if (!f)
+ throw runtime_error(("failed to lock head file " + string(path) +
+ ": " + string(strerror(errno))).c_str());
+
+ string scur;
+ ifstream fin(path);
+ fin >> scur;
+ fin.close();
+ Digest cur(scur);
+
+ if (cur != old) {
+ fclose(f);
+ unlink(lock.c_str());
+ return false;
+ }
+
+ fprintf(f, "%s\n", string(dgst).c_str());
+ fclose(f);
+ fs::rename(lock, path);
+ return true;
+}
+
optional<vector<uint8_t>> FilesystemStorage::loadKey(const Digest & pubref) const
{
fs::path path = keyPath(pubref);
@@ -201,12 +267,37 @@ fs::path FilesystemStorage::objectPath(const Digest & digest) const
fs::path(name.begin() + 2, name.end());
}
+fs::path FilesystemStorage::headPath(UUID type, UUID id) const
+{
+ string stype(type), sid(id);
+ return root/"heads"/
+ fs::path(stype.begin(), stype.end())/
+ fs::path(sid.begin(), sid.end());
+}
+
fs::path FilesystemStorage::keyPath(const Digest & digest) const
{
string name(digest);
return root/"keys"/fs::path(name.begin(), name.end());
}
+FILE * FilesystemStorage::openLockFile(const fs::path & path) const
+{
+ fs::create_directories(path.parent_path());
+
+ // No way to use open exclusively in c++ stdlib
+ FILE *f = nullptr;
+ for (int i = 0; i < 10; i++) {
+ f = fopen(path.c_str(), "wbxe");
+ if (f || errno != EEXIST)
+ break;
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+ }
+
+ return f;
+}
+
+
bool MemoryStorage::contains(const Digest & digest) const
{
return storage.find(digest) != storage.end();
@@ -225,6 +316,57 @@ void MemoryStorage::storeBytes(const Digest & digest, const vector<uint8_t> & co
storage.emplace(digest, content);
}
+optional<Digest> MemoryStorage::headRef(UUID type, UUID id) const
+{
+ auto it = heads.find(type);
+ if (it == heads.end())
+ return nullopt;
+
+ for (const auto & x : it->second)
+ if (get<UUID>(x) == id)
+ return get<Digest>(x);
+
+ return nullopt;
+}
+
+vector<tuple<UUID, Digest>> MemoryStorage::headRefs(UUID type) const
+{
+ auto it = heads.find(type);
+ if (it != heads.end())
+ return it->second;
+ return {};
+}
+
+UUID MemoryStorage::storeHead(UUID type, const Digest & dgst)
+{
+ auto id = UUID::generate();
+ auto it = heads.find(type);
+ if (it == heads.end())
+ heads[type] = { { id, dgst } };
+ else
+ it->second.emplace_back(id, dgst);
+ return id;
+}
+
+bool MemoryStorage::replaceHead(UUID type, UUID id, const Digest & old, const Digest & dgst)
+{
+ auto it = heads.find(type);
+ if (it == heads.end())
+ return false;
+
+ for (auto & x : it->second)
+ if (get<UUID>(x) == id) {
+ if (get<Digest>(x) == old) {
+ get<Digest>(x) = dgst;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ return false;
+}
+
optional<vector<uint8_t>> MemoryStorage::loadKey(const Digest & digest) const
{
auto it = keys.find(digest);
@@ -258,6 +400,42 @@ void ChainStorage::storeBytes(const Digest & digest, const vector<uint8_t> & con
storage->storeBytes(digest, content);
}
+optional<Digest> ChainStorage::headRef(UUID type, UUID id) const
+{
+ if (auto res = storage->headRef(type, id))
+ return res;
+ if (parent)
+ return parent->headRef(type, id);
+ return nullopt;
+}
+
+vector<tuple<UUID, Digest>> ChainStorage::headRefs(UUID type) const
+{
+ auto res = storage->headRefs(type);
+ if (parent)
+ for (auto x : parent->headRefs(type)) {
+ bool add = true;
+ for (const auto & y : res)
+ if (get<UUID>(y) == get<UUID>(x)) {
+ add = false;
+ break;
+ }
+ if (add)
+ res.push_back(x);
+ }
+ return res;
+}
+
+UUID ChainStorage::storeHead(UUID type, const Digest & dgst)
+{
+ return storage->storeHead(type, dgst);
+}
+
+bool ChainStorage::replaceHead(UUID type, UUID id, const Digest & old, const Digest & dgst)
+{
+ return storage->replaceHead(type, id, old, dgst);
+}
+
optional<vector<uint8_t>> ChainStorage::loadKey(const Digest & digest) const
{
if (auto res = storage->loadKey(digest))
@@ -453,6 +631,44 @@ optional<vector<uint8_t>> Storage::loadKey(Ref pubref) const
return p->backend->loadKey(pubref.digest());
}
+optional<Ref> Storage::headRef(UUID type, UUID id) const
+{
+ if (auto dgst = p->backend->headRef(type, id))
+ return ref(*dgst);
+ return nullopt;
+}
+
+vector<tuple<UUID, Ref>> Storage::headRefs(UUID type) const
+{
+ vector<tuple<UUID, Ref>> res;
+ for (auto x : p->backend->headRefs(type))
+ if (auto r = ref(get<Digest>(x)))
+ res.emplace_back(get<UUID>(x), *r);
+ return res;
+}
+
+UUID Storage::storeHead(UUID type, const Ref & ref)
+{
+ return ref.storage().p->backend->storeHead(type, ref.digest());
+}
+
+bool Storage::replaceHead(UUID type, UUID id, const Ref & old, const Ref & ref)
+{
+ return ref.storage().p->backend->replaceHead(type, id, old.digest(), ref.digest());
+}
+
+optional<Ref> Storage::updateHead(UUID type, UUID id, const Ref & old, const std::function<Ref(const Ref &)> & f)
+{
+ Ref r = f(old);
+ if (replaceHead(type, id, old, r))
+ return r;
+
+ if (auto cur = old.storage().headRef(type, id))
+ return updateHead(type, id, *cur, f);
+ else
+ return nullopt;
+}
+
Digest::Digest(const string & str)
{
diff --git a/src/storage.h b/src/storage.h
index 1635d40..18ac1ad 100644
--- a/src/storage.h
+++ b/src/storage.h
@@ -13,6 +13,7 @@ using std::shared_ptr;
using std::unique_ptr;
using std::unordered_map;
using std::unordered_set;
+using std::tuple;
using std::variant;
using std::vector;
@@ -29,6 +30,11 @@ public:
virtual optional<vector<uint8_t>> loadBytes(const Digest &) const = 0;
virtual void storeBytes(const Digest &, const vector<uint8_t> &) = 0;
+ virtual optional<Digest> headRef(UUID type, UUID id) const = 0;
+ virtual vector<tuple<UUID, Digest>> headRefs(UUID type) const = 0;
+ virtual UUID storeHead(UUID type, const Digest & dgst) = 0;
+ virtual bool replaceHead(UUID type, UUID id, const Digest & old, const Digest & dgst) = 0;
+
virtual optional<vector<uint8_t>> loadKey(const Digest &) const = 0;
virtual void storeKey(const Digest &, const vector<uint8_t> &) = 0;
};
@@ -44,6 +50,11 @@ public:
virtual optional<vector<uint8_t>> loadBytes(const Digest &) const override;
virtual void storeBytes(const Digest &, const vector<uint8_t> &) override;
+ virtual optional<Digest> headRef(UUID type, UUID id) const override;
+ virtual vector<tuple<UUID, Digest>> headRefs(UUID type) const override;
+ virtual UUID storeHead(UUID type, const Digest & dgst) override;
+ virtual bool replaceHead(UUID type, UUID id, const Digest & old, const Digest & dgst) override;
+
virtual optional<vector<uint8_t>> loadKey(const Digest &) const override;
virtual void storeKey(const Digest &, const vector<uint8_t> &) override;
@@ -51,8 +62,11 @@ private:
static constexpr size_t CHUNK = 16384;
fs::path objectPath(const Digest &) const;
+ fs::path headPath(UUID id, UUID type) const;
fs::path keyPath(const Digest &) const;
+ FILE * openLockFile(const fs::path & path) const;
+
fs::path root;
};
@@ -67,11 +81,17 @@ public:
virtual optional<vector<uint8_t>> loadBytes(const Digest &) const override;
virtual void storeBytes(const Digest &, const vector<uint8_t> &) override;
+ virtual optional<Digest> headRef(UUID type, UUID id) const override;
+ virtual vector<tuple<UUID, Digest>> headRefs(UUID type) const override;
+ virtual UUID storeHead(UUID type, const Digest & dgst) override;
+ virtual bool replaceHead(UUID type, UUID id, const Digest & old, const Digest & dgst) override;
+
virtual optional<vector<uint8_t>> loadKey(const Digest &) const override;
virtual void storeKey(const Digest &, const vector<uint8_t> &) override;
private:
unordered_map<Digest, vector<uint8_t>> storage;
+ unordered_map<UUID, vector<tuple<UUID, Digest>>> heads;
unordered_map<Digest, vector<uint8_t>> keys;
};
@@ -89,6 +109,11 @@ public:
virtual optional<vector<uint8_t>> loadBytes(const Digest &) const override;
virtual void storeBytes(const Digest &, const vector<uint8_t> &) override;
+ virtual optional<Digest> headRef(UUID type, UUID id) const override;
+ virtual vector<tuple<UUID, Digest>> headRefs(UUID type) const override;
+ virtual UUID storeHead(UUID type, const Digest & dgst) override;
+ virtual bool replaceHead(UUID type, UUID id, const Digest & old, const Digest & dgst) override;
+
virtual optional<vector<uint8_t>> loadKey(const Digest &) const override;
virtual void storeKey(const Digest &, const vector<uint8_t> &) override;