#pragma once #include "erebos/storage.h" #include #include #include #include namespace fs = std::filesystem; using std::function; using std::mutex; using std::optional; using std::shared_future; 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> loadBytes(const Digest &) const = 0; virtual void storeBytes(const Digest &, const vector &) = 0; virtual optional headRef(UUID type, UUID id) const = 0; virtual vector> 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 void watchHead(UUID type, const function &) = 0; virtual optional> loadKey(const Digest &) const = 0; virtual void storeKey(const Digest &, const vector &) = 0; }; class FilesystemStorage : public StorageBackend { public: FilesystemStorage(const fs::path &); virtual ~FilesystemStorage(); virtual bool contains(const Digest &) const override; virtual optional> loadBytes(const Digest &) const override; virtual void storeBytes(const Digest &, const vector &) override; virtual optional headRef(UUID type, UUID id) const override; virtual vector> 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 void watchHead(UUID type, const function &) override; virtual optional> loadKey(const Digest &) const override; virtual void storeKey(const Digest &, const vector &) 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; unordered_multimap> watchers; unordered_map watchMap; }; class MemoryStorage : public StorageBackend { public: MemoryStorage() = default; virtual ~MemoryStorage() = default; virtual bool contains(const Digest &) const override; virtual optional> loadBytes(const Digest &) const override; virtual void storeBytes(const Digest &, const vector &) override; virtual optional headRef(UUID type, UUID id) const override; virtual vector> 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 void watchHead(UUID type, const function &) override; virtual optional> loadKey(const Digest &) const override; virtual void storeKey(const Digest &, const vector &) override; private: unordered_map> storage; unordered_map>> heads; unordered_map> keys; mutex watcherLock; unordered_multimap> watchers; }; class ChainStorage : public StorageBackend { public: ChainStorage(shared_ptr storage): ChainStorage(std::move(storage), nullptr) {} ChainStorage(shared_ptr storage, unique_ptr parent): storage(std::move(storage)), parent(std::move(parent)) {} virtual ~ChainStorage() = default; virtual bool contains(const Digest &) const override; virtual optional> loadBytes(const Digest &) const override; virtual void storeBytes(const Digest &, const vector &) override; virtual optional headRef(UUID type, UUID id) const override; virtual vector> 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 void watchHead(UUID type, const function &) override; virtual optional> loadKey(const Digest &) const override; virtual void storeKey(const Digest &, const vector &) override; private: shared_ptr storage; unique_ptr parent; }; struct PartialStorage::Priv { shared_ptr backend; Digest storeBytes(const vector &) const; optional> loadBytes(const Digest & digest) const; template optional copy(const typename S::Ref &, vector *) const; template optional copy(const ObjectT &, vector *) const; }; struct PartialRef::Priv { const unique_ptr storage; const Digest digest; }; vector> collectStoredObjects(const Stored &); }