summaryrefslogtreecommitdiff
path: root/src/storage.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/storage.h')
-rw-r--r--src/storage.h201
1 files changed, 201 insertions, 0 deletions
diff --git a/src/storage.h b/src/storage.h
new file mode 100644
index 0000000..c6b5ed2
--- /dev/null
+++ b/src/storage.h
@@ -0,0 +1,201 @@
+#pragma once
+
+#include "erebos/storage.h"
+
+#include <functional>
+#include <mutex>
+#include <unordered_map>
+#include <unordered_set>
+
+namespace fs = std::filesystem;
+
+using std::function;
+using std::mutex;
+using std::optional;
+using std::shared_ptr;
+using std::unique_ptr;
+using std::unordered_map;
+using std::unordered_multimap;
+using std::unordered_set;
+using std::tuple;
+using std::variant;
+using std::vector;
+
+namespace erebos {
+
+class StorageBackend
+{
+public:
+ StorageBackend() = default;
+ virtual ~StorageBackend() = default;
+
+ virtual bool contains(const Digest &) const = 0;
+
+ 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 int watchHead(UUID type, const function<void(UUID id, const Digest &)> &) = 0;
+ virtual void unwatchHead(UUID type, int watchId) = 0;
+
+ virtual optional<vector<uint8_t>> loadKey(const Digest &) const = 0;
+ virtual void storeKey(const Digest &, const vector<uint8_t> &) = 0;
+};
+
+class StorageWatchCallback
+{
+public:
+ StorageWatchCallback(int id, const function<void(UUID, const Digest &)> callback):
+ id(id), callback(callback) {}
+
+ void schedule(UUID, const Digest &);
+ void run();
+
+ const int id;
+
+private:
+ const function<void(UUID, const Digest &)> callback;
+
+ std::recursive_mutex runMutex;
+ optional<tuple<UUID, Digest>> scheduled;
+};
+
+class FilesystemStorage : public StorageBackend
+{
+public:
+ FilesystemStorage(const fs::path &);
+ virtual ~FilesystemStorage();
+
+ virtual bool contains(const Digest &) const override;
+
+ 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 int watchHead(UUID type, const function<void(UUID id, const Digest &)> &) override;
+ virtual void unwatchHead(UUID type, int watchId) override;
+
+ virtual optional<vector<uint8_t>> loadKey(const Digest &) const override;
+ virtual void storeKey(const Digest &, const vector<uint8_t> &) override;
+
+private:
+ void inotifyWatch();
+
+ static constexpr size_t CHUNK = 16384;
+
+ fs::path objectPath(const Digest &) const;
+ fs::path headPath(UUID id) 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;
+
+ mutex watcherLock;
+ std::thread watcherThread;
+ int inotify = -1;
+ int inotifyWakeup = -1;
+ int nextWatcherId = 1;
+ unordered_multimap<UUID, shared_ptr<StorageWatchCallback>> watchers;
+ unordered_map<int, UUID> watchMap;
+};
+
+class MemoryStorage : public StorageBackend
+{
+public:
+ MemoryStorage() = default;
+ virtual ~MemoryStorage() = default;
+
+ virtual bool contains(const Digest &) const override;
+
+ 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 int watchHead(UUID type, const function<void(UUID id, const Digest &)> &) override;
+ virtual void unwatchHead(UUID type, int watchId) 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;
+
+ mutex watcherLock;
+ int nextWatcherId = 1;
+ unordered_multimap<UUID, shared_ptr<StorageWatchCallback>> watchers;
+};
+
+class ChainStorage : public StorageBackend
+{
+public:
+ ChainStorage(shared_ptr<StorageBackend> storage):
+ ChainStorage(std::move(storage), nullptr) {}
+ ChainStorage(shared_ptr<StorageBackend> storage, unique_ptr<ChainStorage> parent):
+ storage(std::move(storage)), parent(std::move(parent)) {}
+ virtual ~ChainStorage() = default;
+
+ virtual bool contains(const Digest &) const override;
+
+ 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 int watchHead(UUID type, const function<void(UUID id, const Digest &)> &) override;
+ virtual void unwatchHead(UUID type, int watchId) override;
+
+ virtual optional<vector<uint8_t>> loadKey(const Digest &) const override;
+ virtual void storeKey(const Digest &, const vector<uint8_t> &) override;
+
+private:
+ shared_ptr<StorageBackend> storage;
+ unique_ptr<ChainStorage> parent;
+
+ mutex watcherLock;
+ int nextWatcherId = 1;
+ unordered_map<int, tuple<int, int>> watchers;
+};
+
+struct PartialStorage::Priv
+{
+ shared_ptr<StorageBackend> backend;
+
+ Digest storeBytes(const vector<uint8_t> &) const;
+ optional<vector<uint8_t>> loadBytes(const Digest & digest) const;
+
+ template<class S>
+ optional<Digest> copy(const typename S::Ref &, vector<Digest> *) const;
+ template<class S>
+ optional<Digest> copy(const ObjectT<S> &, vector<Digest> *) const;
+
+ mutable mutex generationCacheLock {};
+ mutable unordered_map<Digest, Generation> generationCache {};
+
+ mutable mutex rootsCacheLock {};
+ mutable unordered_map<Digest, vector<Digest>> rootsCache {};
+};
+
+struct PartialRef::Priv
+{
+ const unique_ptr<PartialStorage> storage;
+ const Digest digest;
+};
+
+vector<Stored<Object>> collectStoredObjects(const Stored<Object> &);
+
+}