/** * caching for a tree-like data structure (like Nix values) * * The cache is an sqlite db whose rows are the nodes of the tree, with a * pointer to their parent (except for the root of course) */ #pragma once #include "sync.hh" #include "hash.hh" #include "symbol-table.hh" #include #include namespace nix::tree_cache { struct AttrDb; class Cursor; class Cache : public std::enable_shared_from_this { private: friend class Cursor; /** * The database holding the cache */ std::shared_ptr db; SymbolTable & symbols; /** * Distinguished symbol indicating the root of the tree */ const Symbol rootSymbol; public: Cache( const Hash & useCache, SymbolTable & symbols ); static std::shared_ptr tryCreate(const Hash & useCache, SymbolTable & symbols); Cursor * getRoot(); /** * Flush the cache to disk */ void commit(); }; enum AttrType { Unknown = 0, Attrs = 1, String = 2, Bool = 3, Int = 4, Double = 5, Thunk = 6, Missing = 7, // Missing fields of attribute sets Failed = 8, }; struct attributeSet_t {}; struct unknown_t {}; struct thunk_t {}; struct failed_t { string error; }; struct missing_t { Symbol attrName; }; typedef uint64_t AttrId; typedef std::pair AttrKey; typedef std::pair>> string_t; typedef std::variant< attributeSet_t, string_t, unknown_t, thunk_t, missing_t, failed_t, bool, int64_t, double > AttrValue; struct RawValue { AttrType type; std::optional value; std::vector> context; std::string serializeContext() const; static const RawValue fromVariant(const AttrValue&); AttrValue toVariant() const; }; /** * View inside the cache. * * A `Cursor` represents a node in the cached tree (be it a leaf or not) */ class Cursor : public std::enable_shared_from_this { /** * The overall cache of which this cursor is a view */ ref root; typedef std::optional> Parent; std::optional parentId; Symbol label; std::pair cachedValue; /** * Get the identifier for this node in the database */ AttrKey getKey(); public: using Ref = Cursor*; // Create a new cache entry Cursor(ref root, const Parent & parent, const AttrValue&); // Build a cursor from an existing cache entry Cursor(ref root, const Parent & parent, const AttrId& id, const AttrValue&); AttrValue getCachedValue(); void setValue(const AttrValue & v); Ref addChild(const Symbol & attrPath, const AttrValue & v); Ref findAlongAttrPath(const std::vector & attrPath); Ref maybeGetAttr(const Symbol & attrPath); std::vector getChildren(); std::optional> getChildrenAtPath(const std::vector & attrPath); }; }