Safe Haskell | None |
---|---|
Language | Haskell2010 |
Hash addressed store in file system.
Associates a key (ContentHash
)
with an item in the store. An item can either be
Missing
,
Pending
, or
Complete
.
The state is persisted in the file system.
Items are stored under a path derived from their hash. Therefore, there can be no two copies of the same item in the store. If two keys are associated with the same item, then there will be only one copy of that item in the store.
The store is thread-safe and multi-process safe.
It is assumed that the user that the process is running under is the owner of the store root, or has permission to create it if missing.
It is assumed that the store root and its immediate contents are not modified externally. The contents of pending items may be modified externally.
Implementation notes:
The hash of an item can only be determined once it is completed. If that hash already exists in the store, then the new item is discarded.
Store state is persisted in the file-system:
- Pending items are stored writable under the path
pending-<key>
. - Complete items are stored read-only under the path
item-<hash>
, with a link undercomplete-<key>
pointing to that directory.
Synopsis
- withStore :: (MonadIO m, MonadMask m) => Path Abs Dir -> (ContentStore -> m a) -> m a
- open :: Path Abs Dir -> IO ContentStore
- close :: ContentStore -> IO ()
- data CacherM m i o
- = NoCache
- | Cache {
- cacherKey :: Int -> i -> m ContentHash
- cacherStoreValue :: o -> ByteString
- cacherReadValue :: ByteString -> o
- type Cacher = CacherM Identity
- defaultCacherWithIdent :: forall m i o. (ContentHashable m i, Store o) => Int -> CacherM m i o
- defaultIOCacherWithIdent :: (MonadIO m, ContentHashable IO i, Store o) => Int -> CacherM m i o
- cacheKleisliIO :: (MonadIO m, MonadUnliftIO m, MonadMask m, Cacher m remoteCache) => Maybe Int -> CacherM m i o -> ContentStore -> remoteCache -> (i -> m o) -> i -> m o
- putInStore :: (MonadIO m, MonadMask m, MonadUnliftIO m, Cacher m remoteCacher, ContentHashable IO t) => ContentStore -> remoteCacher -> (ContentHash -> m ()) -> (Path Abs Dir -> t -> m ()) -> t -> m Item
- contentPath :: ContentStore -> Content t -> Path Abs t
- listAll :: MonadIO m => ContentStore -> m ([ContentHash], [ContentHash], [Item])
- listPending :: MonadIO m => ContentStore -> m [ContentHash]
- listComplete :: MonadIO m => ContentStore -> m [ContentHash]
- listItems :: MonadIO m => ContentStore -> m [Item]
- query :: MonadIO m => ContentStore -> ContentHash -> m (Status () () ())
- isMissing :: MonadIO m => ContentStore -> ContentHash -> m Bool
- isPending :: MonadIO m => ContentStore -> ContentHash -> m Bool
- isComplete :: MonadIO m => ContentStore -> ContentHash -> m Bool
- lookup :: MonadIO m => ContentStore -> ContentHash -> m (Status () () Item)
- lookupOrWait :: MonadIO m => ContentStore -> ContentHash -> m (Status () (Async Update) Item)
- waitUntilComplete :: MonadIO m => ContentStore -> ContentHash -> m (Maybe Item)
- cacheComputation :: (MonadIO m, MonadUnliftIO m, MonadMask m, Cacher m remoteCache) => ContentStore -> remoteCache -> m () -> ContentHash -> (Path Abs Dir -> m a) -> m (Maybe a, Item)
- constructIfMissing :: (MonadIO m, MonadUnliftIO m, MonadMask m, Cacher m remoteCache) => ContentStore -> remoteCache -> ContentHash -> m (Status (Path Abs Dir) () Item)
- withConstructIfMissing :: (MonadIO m, MonadUnliftIO m, MonadMask m, Cacher m remoteCache) => ContentStore -> remoteCache -> m () -> ContentHash -> (Path Abs Dir -> m (Either e a)) -> m (Status e () (Maybe a, Item))
- markPending :: MonadIO m => ContentStore -> ContentHash -> m (Path Abs Dir)
- markComplete :: MonadIO m => ContentStore -> ContentHash -> m Item
- removeFailed :: MonadIO m => ContentStore -> ContentHash -> m ()
- removeForcibly :: MonadIO m => ContentStore -> ContentHash -> m ()
- removeItemForcibly :: MonadIO m => ContentStore -> Item -> m ()
- assignAlias :: MonadIO m => ContentStore -> Alias -> Item -> m ()
- lookupAlias :: MonadIO m => ContentStore -> Alias -> m (Maybe Item)
- removeAlias :: MonadIO m => ContentStore -> Alias -> m ()
- listAliases :: MonadIO m => ContentStore -> m [(Alias, Item, ContentHash)]
- getBackReferences :: MonadIO m => ContentStore -> Item -> m [ContentHash]
- setInputs :: MonadIO m => ContentStore -> ContentHash -> [Item] -> m ()
- getInputs :: MonadIO m => ContentStore -> ContentHash -> m [Item]
- setMetadata :: (ToField k, ToField v, MonadIO m) => ContentStore -> ContentHash -> k -> v -> m ()
- getMetadata :: (ToField k, FromField v, MonadIO m) => ContentStore -> ContentHash -> k -> m (Maybe v)
- createMetadataFile :: MonadIO m => ContentStore -> ContentHash -> Path Rel File -> m (Path Abs File, Handle)
- getMetadataFile :: MonadIO m => ContentStore -> ContentHash -> Path Rel File -> m (Maybe (Path Abs File))
- itemHash :: Item -> ContentHash
- itemPath :: ContentStore -> Item -> Path Abs Dir
- itemRelPath :: Item -> Path Rel Dir
- contentItem :: Content t -> Item
- contentFilename :: Content File -> Path Rel File
- root :: ContentStore -> Path Abs Dir
- data ContentStore
- data Item
- data Content t where
- (^</>) :: Content Dir -> Path Rel t -> Content t
- newtype Alias = Alias {}
- data Status missing pending complete
- type Status_ = Status () () ()
- data Update
- data StoreError
Open/Close
withStore :: (MonadIO m, MonadMask m) => Path Abs Dir -> (ContentStore -> m a) -> m a Source #
Open the store under the given root and perform the given action. Closes the store once the action is complete
See also: open
open :: Path Abs Dir -> IO ContentStore Source #
open root
opens a store under the given root directory.
The root directory is created if necessary.
It is not safe to have multiple store objects refer to the same root directory.
close :: ContentStore -> IO () Source #
Free the resources associated with the given store object.
The store object may not be used afterwards.
High-level API
A cacher is responsible for controlling how steps are cached.
NoCache | This step cannot be cached (default). |
Cache | |
|
defaultCacherWithIdent Source #
:: forall m i o. (ContentHashable m i, Store o) | |
=> Int | Seed for the cacher |
-> CacherM m i o |
Constructs a Cacher
that will use hashability of input and
serializability of output to make a step cacheable
defaultIOCacherWithIdent Source #
Looks for a CacherM IO
, then lifts it
:: (MonadIO m, MonadUnliftIO m, MonadMask m, Cacher m remoteCache) | |
=> Maybe Int | This can be used to disambiguate the same program run in
multiple configurations. If Nothing, then it means this
program has no identity, this implies that steps will be
executed without cache, even if |
-> CacherM m i o | |
-> ContentStore | |
-> remoteCache | |
-> (i -> m o) | |
-> i | |
-> m o |
Caches a Kleisli of some MonadIO action in the store given the required properties
:: (MonadIO m, MonadMask m, MonadUnliftIO m, Cacher m remoteCacher, ContentHashable IO t) | |
=> ContentStore | |
-> remoteCacher | |
-> (ContentHash -> m ()) | In case an exception occurs |
-> (Path Abs Dir -> t -> m ()) | The action that writes to the new store directory |
-> t | |
-> m Item | The Item in the store to which |
Caches an action that writes content-addressed data to the store. Returns the Item of the written content.
contentPath :: ContentStore -> Content t -> Path Abs t Source #
The absolute path to content within the store.
List Contents
listAll :: MonadIO m => ContentStore -> m ([ContentHash], [ContentHash], [Item]) Source #
List all elements in the store
(pending keys, completed keys, completed items)
.
listPending :: MonadIO m => ContentStore -> m [ContentHash] Source #
List all pending keys in the store.
listComplete :: MonadIO m => ContentStore -> m [ContentHash] Source #
List all completed keys in the store.
Query/Lookup
query :: MonadIO m => ContentStore -> ContentHash -> m (Status () () ()) Source #
Query the state of the item under the given key.
isMissing :: MonadIO m => ContentStore -> ContentHash -> m Bool Source #
Check if there is no complete or pending item under the given key.
isPending :: MonadIO m => ContentStore -> ContentHash -> m Bool Source #
Check if there is a pending item under the given key.
isComplete :: MonadIO m => ContentStore -> ContentHash -> m Bool Source #
Check if there is a completed item under the given key.
lookup :: MonadIO m => ContentStore -> ContentHash -> m (Status () () Item) Source #
Query the state under the given key and return the item if completed. Doesn't block if the item is pending.
lookupOrWait :: MonadIO m => ContentStore -> ContentHash -> m (Status () (Async Update) Item) Source #
Query the state under the given key and return the item if completed.
Return an Async
to await an update, if pending.
waitUntilComplete :: MonadIO m => ContentStore -> ContentHash -> m (Maybe Item) Source #
Query the state under the given key and return the item once completed.
Blocks if the item is pending.
Returns Nothing
if the item is missing, or failed to be completed.
Construct Items
:: (MonadIO m, MonadUnliftIO m, MonadMask m, Cacher m remoteCache) | |
=> ContentStore | |
-> remoteCache | |
-> m () | In case an exception occurs |
-> ContentHash | A ContentHash to identify the computation inputs |
-> (Path Abs Dir -> m a) | The computation to cache, receving the path of a store folder to which it should write its results |
-> m (Maybe a, Item) | The result if it was just computed, and the item corresponding to the store folder |
Runs a computation only if the ContentHash isn't already associated to an entry in the store
constructIfMissing :: (MonadIO m, MonadUnliftIO m, MonadMask m, Cacher m remoteCache) => ContentStore -> remoteCache -> ContentHash -> m (Status (Path Abs Dir) () Item) Source #
Atomically query the state under the given key and mark pending if missing.
withConstructIfMissing Source #
:: (MonadIO m, MonadUnliftIO m, MonadMask m, Cacher m remoteCache) | |
=> ContentStore | |
-> remoteCache | |
-> m () | In case an exception occurs (to log something for instance) |
-> ContentHash | |
-> (Path Abs Dir -> m (Either e a)) | |
-> m (Status e () (Maybe a, Item)) |
Atomically query the state under the given key and mark pending if missing. Execute the given function to construct the item, mark as complete on success and remove on failure. Forcibly removes if an uncaught exception occurs during item construction.
markPending :: MonadIO m => ContentStore -> ContentHash -> m (Path Abs Dir) Source #
Mark a non-existent item as pending.
Creates the build directory and returns its path.
See also: constructIfMissing
.
markComplete :: MonadIO m => ContentStore -> ContentHash -> m Item Source #
Mark a pending item as complete.
Remove Contents
removeFailed :: MonadIO m => ContentStore -> ContentHash -> m () Source #
Remove a pending item.
It is the callers responsibility to ensure that no other threads or processes will attempt to access the item's contents afterwards.
removeForcibly :: MonadIO m => ContentStore -> ContentHash -> m () Source #
Remove a key association independent of the corresponding item state. Do nothing if no item exists under the given key.
It is the callers responsibility to ensure that no other threads or processes will attempt to access the contents afterwards.
Note, this will leave an orphan item behind if no other keys point to it. There is no garbage collection mechanism in place at the moment.
removeItemForcibly :: MonadIO m => ContentStore -> Item -> m () Source #
Remove a completed item in the store. Do nothing if not completed.
It is the callers responsibility to ensure that no other threads or processes will attempt to access the contents afterwards.
Note, this will leave keys pointing to that item dangling. There is no garbage collection mechanism in place at the moment.
Aliases
assignAlias :: MonadIO m => ContentStore -> Alias -> Item -> m () Source #
Link the given alias to the given item. If the alias existed before it is overwritten.
lookupAlias :: MonadIO m => ContentStore -> Alias -> m (Maybe Item) Source #
Lookup an item under the given alias.
Returns Nothing
if the alias does not exist.
removeAlias :: MonadIO m => ContentStore -> Alias -> m () Source #
Remove the given alias.
listAliases :: MonadIO m => ContentStore -> m [(Alias, Item, ContentHash)] Source #
List all aliases and the respective items.
Metadata
getBackReferences :: MonadIO m => ContentStore -> Item -> m [ContentHash] Source #
Get all hashes that resulted in the given item.
setInputs :: MonadIO m => ContentStore -> ContentHash -> [Item] -> m () Source #
Define the input items to a subtree.
getInputs :: MonadIO m => ContentStore -> ContentHash -> m [Item] Source #
Get the input items to a subtree if any were defined.
setMetadata :: (ToField k, ToField v, MonadIO m) => ContentStore -> ContentHash -> k -> v -> m () Source #
Set a metadata entry on an item.
getMetadata :: (ToField k, FromField v, MonadIO m) => ContentStore -> ContentHash -> k -> m (Maybe v) Source #
Retrieve a metadata entry on an item, or Nothing
if missing.
createMetadataFile :: MonadIO m => ContentStore -> ContentHash -> Path Rel File -> m (Path Abs File, Handle) Source #
Create and open a new metadata file on a pending item in write mode.
getMetadataFile :: MonadIO m => ContentStore -> ContentHash -> Path Rel File -> m (Maybe (Path Abs File)) Source #
Return the path to a metadata file if it exists.
Accessors
itemHash :: Item -> ContentHash Source #
contentItem :: Content t -> Item Source #
Store item containing the given content.
Types
data ContentStore Source #
A hash addressed store on the file system.
A completed item in the ContentStore
.
Instances
Eq Item Source # | |
Ord Item Source # | |
Show Item Source # | |
Generic Item Source # | |
Hashable Item Source # | |
Defined in Data.CAS.ContentStore | |
ToJSON Item Source # | |
Defined in Data.CAS.ContentStore | |
FromJSON Item Source # | |
Store Item Source # | |
Monad m => ContentHashable m Item Source # | |
Defined in Data.CAS.ContentStore contentHashUpdate :: Context SHA256 -> Item -> m (Context SHA256) # contentHash :: Item -> m ContentHash # | |
type Rep Item Source # | |
Defined in Data.CAS.ContentStore type Rep Item = D1 ('MetaData "Item" "Data.CAS.ContentStore" "cas-store-1.1.1-4N47vgFLWRf7QdOmm8W33j" 'True) (C1 ('MetaCons "Item" 'PrefixI 'True) (S1 ('MetaSel ('Just "itemHash") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 ContentHash))) |
File or directory within a content store Item
.
Instances
Monad m => ContentHashable m (Content File) Source # | |
Defined in Data.CAS.ContentStore contentHashUpdate :: Context SHA256 -> Content File -> m (Context SHA256) # contentHash :: Content File -> m ContentHash # | |
Monad m => ContentHashable m (Content Dir) Source # | |
Defined in Data.CAS.ContentStore contentHashUpdate :: Context SHA256 -> Content Dir -> m (Context SHA256) # contentHash :: Content Dir -> m ContentHash # | |
Eq (Content t) Source # | |
Show (Content t) Source # | |
(^</>) :: Content Dir -> Path Rel t -> Content t infixl 4 Source #
Append to the path within a store item.
Instances
Eq Alias Source # | |
Ord Alias Source # | |
Show Alias Source # | |
FromField Alias Source # | |
Defined in Data.CAS.ContentStore | |
ToField Alias Source # | |
Defined in Data.CAS.ContentStore | |
Store Alias Source # | |
ContentHashable IO Alias Source # | |
Defined in Data.CAS.ContentStore contentHashUpdate :: Context SHA256 -> Alias -> IO (Context SHA256) # contentHash :: Alias -> IO ContentHash # |
data Status missing pending complete Source #
Status of an item in the store.
Missing missing | The item does not exist, yet. |
Pending pending | The item is under construction and not ready for consumption. |
Complete complete | The item is complete and ready for consumption. |
Update about the status of a pending item.
data StoreError Source #
Errors that can occur when interacting with the store.
NotPending ContentHash | An item is not under construction when it should be. |
AlreadyPending ContentHash | An item is already under construction when it should be missing. |
AlreadyComplete ContentHash | An item is already complete when it shouldn't be. |
CorruptedLink ContentHash FilePath | The link under the given hash points to an invalid path. |
FailedToConstruct ContentHash | A failure occurred while waiting for the item to be constructed. |
IncompatibleStoreVersion (Path Abs Dir) Int Int |
|
MalformedMetadataEntry ContentHash SQLData |
|
Instances
Show StoreError Source # | |
Defined in Data.CAS.ContentStore showsPrec :: Int -> StoreError -> ShowS # show :: StoreError -> String # showList :: [StoreError] -> ShowS # | |
Exception StoreError Source # | |
Defined in Data.CAS.ContentStore toException :: StoreError -> SomeException # fromException :: SomeException -> Maybe StoreError # displayException :: StoreError -> String # |