packages feed

hashed-storage 0.4.6 → 0.4.7

raw patch · 5 files changed

+64/−61 lines, 5 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

+ Storage.Hashed.Monad: currentDirectory :: (TreeRO m) => m AnchoredPath
- Storage.Hashed.Monad: replaceItem :: (MonadError e m, Monad m) => AnchoredPath -> Maybe (TreeItem m) -> TreeMonad m ()
+ Storage.Hashed.Monad: replaceItem :: (MonadError e m, Functor m, Monad m) => AnchoredPath -> Maybe (TreeItem m) -> TreeMonad m ()
- Storage.Hashed.Monad: tree :: TreeState m -> Tree m
+ Storage.Hashed.Monad: tree :: TreeState m -> (Tree m)
- Storage.Hashed.Tree: items :: Tree m -> Map Name (TreeItem m)
+ Storage.Hashed.Tree: items :: Tree m -> (Map Name (TreeItem m))

Files

Storage/Hashed/Darcs.hs view
@@ -213,9 +213,6 @@ -- | Run a 'TreeIO' @action@ in a hashed setting. The @initial@ tree is assumed -- to be fully available from the @directory@, and any changes will be written -- out to same. Please note that actual filesystem files are never removed.------ XXX This somehow manages to leak memory, in some usege scenarios (apparently--- not even all). The only reproducer known so far is \"gorsvet pull\". hashedTreeIO :: TreeIO a -- ^ action              -> Tree IO -- ^ initial              -> FilePath -- ^ directory
Storage/Hashed/Monad.hs view
@@ -7,13 +7,11 @@ -- generic, and a number of actual implementations can be used. This module -- provides just 'virtualTreeIO' that never writes any changes, but may trigger -- filesystem reads as appropriate.------ XXX This currently does not work as advertised and the monads leak--- memory. So far, I'm at a loss why this happens. module Storage.Hashed.Monad     ( virtualTreeIO, virtualTreeMonad     , readFile, writeFile, createDirectory, rename, unlink     , fileExists, directoryExists, exists, withDirectory+    , currentDirectory     , tree, TreeState, TreeMonad, TreeIO, runTreeMonad     , PathSet, initialState, replaceItem     ) where@@ -31,7 +29,6 @@ import Data.Maybe( isNothing, isJust )  import qualified Data.ByteString.Lazy.Char8 as BL-import qualified Data.ByteString.Char8( ) import Control.Monad.RWS.Strict import qualified Data.Set as S @@ -39,9 +36,9 @@  -- | Internal state of the 'TreeIO' monad. Keeps track of the current Tree -- content, unsync'd changes and a current working directory (of the monad).-data TreeState m = TreeState { tree :: Tree m-                             , changed :: PathSet-                             , changesize :: Int64+data TreeState m = TreeState { tree :: !(Tree m)+                             , changed :: !PathSet+                             , changesize :: !Int64                              , sync :: PathSet -> TreeMonad m () }  -- | A 'TreeIO' monad. A sort of like IO but it keeps a 'TreeState' around as well,@@ -106,23 +103,41 @@ virtualTreeIO :: TreeIO a -> Tree IO -> IO (a, Tree IO) virtualTreeIO = virtualTreeMonad -replaceItem :: (MonadError e m, Monad m) => AnchoredPath -> Maybe (TreeItem m) -> TreeMonad m ()+-- | Modifies an item in the current Tree. This action keeps an account of the+-- modified data, in changed and changesize, for subsequent flush+-- operations. Any modifications (as in "modifyTree") are allowed.+modifyItem :: (MonadError e m, Functor m, Monad m)+            => AnchoredPath -> Maybe (TreeItem m) -> TreeMonad m ()+modifyItem path item = do+  path' <- (`catPaths` path) `fmap` currentDirectory+  let paths = let (AnchoredPath x) = path'+              in S.fromList $ map AnchoredPath $ inits x+  change <- changedSize path' item+  modify $ \st -> st { tree = modifyTree (tree st) path' item+                     , changed = (S.union paths (changed st))+                     , changesize = (changesize st + change) }++-- | Replace an item with a new version without modifying the content of the+-- tree. This does not do any change tracking. Ought to be only used from a+-- 'sync' implementation for a particular storage format. The presumed use-case+-- is that an existing in-memory Blob is replaced with a one referring to an+-- on-disk file.+replaceItem :: (MonadError e m, Functor m, Monad m)+            => AnchoredPath -> Maybe (TreeItem m) -> TreeMonad m () replaceItem path item = do   path' <- (`catPaths` path) `fmap` currentDirectory   modify $ \st -> st { tree = modifyTree (tree st) path' item } --- | Internal. Mark a given path as changed, so the next sync will flush the--- modified object to disk.-markChanged :: (Functor m, Monad m) => AnchoredPath -> TreeMonad m ()-markChanged p = do-  x <- get-  size <- lift $ case findFile (tree x) p of-                   Just b -> BL.length `fmap` readBlob b-                   Nothing -> return 0-  put $ x { changed = S.union paths (changed x)-          , changesize = changesize x + size }-    where paths = let (AnchoredPath x) = p-                   in S.fromList $ map AnchoredPath $ inits x+changedSize :: (MonadError e m, Functor m, Monad m)+            => AnchoredPath -> Maybe (TreeItem m) -> TreeMonad m Int64+changedSize path item = do+    x <- get+    let ch = S.member path (changed x)+        size (Just (File b)) = lift (BL.length `fmap` readBlob b)+        size _ = return 0+    oldsize <- size $ find (tree x) path+    newsize <- size item+    return $! (if ch then newsize - oldsize else newsize)  -- | If buffers are becoming large, sync, otherwise do nothing. maybeFlush :: (Monad m) => TreeMonad m ()@@ -163,8 +178,7 @@ instance (Functor m, Monad m, MonadError e m) => TreeRW (TreeMonad m) where     writeFile p con =         do expandTo p-           replaceItem p (Just blob)-           markChanged p+           modifyItem p (Just blob)            maybeFlush         where blob = File $ Blob (return con) hash               hash = NoHash -- we would like to say "sha256 con" here, but due@@ -175,11 +189,11 @@      createDirectory p =         do expandTo p-           replaceItem p $ Just $ SubTree emptyTree+           modifyItem p $ Just $ SubTree emptyTree      unlink p =         do expandTo p-           replaceItem p Nothing+           modifyItem p Nothing      rename from to =         do expandTo from@@ -189,5 +203,5 @@            unless (isNothing found_to) $                   fail $ "Error renaming: destination " ++ show to ++ " exists."            unless (isNothing item) $ do-                  replaceItem to item-                  replaceItem from Nothing+                  modifyItem to item+                  modifyItem from Nothing
Storage/Hashed/Plain.hs view
@@ -28,7 +28,7 @@ import Storage.Hashed.Tree( Tree(), TreeItem(..)                           , Blob(..), makeTree                           , list, readBlob, find, modifyTree )-import Storage.Hashed.Monad( TreeIO, runTreeMonad, initialState, tree )+import Storage.Hashed.Monad( TreeIO, runTreeMonad, initialState, tree, replaceItem ) import qualified Data.Set as S import Control.Monad.State( liftIO, gets, modify ) @@ -81,8 +81,7 @@                   Just (File b) -> do                     liftIO $ readBlob b >>= BL.writeFile path                     let nblob = File $ Blob (BL.readFile path) NoHash-                    modify $ \st -> st { tree = modifyTree (tree st) c-                                                           (Just nblob) }+                    replaceItem c (Just nblob)                   Just (SubTree _) ->                       liftIO $ createDirectoryIfMissing False path                   _ -> fail $ "Foo at " ++ path
Storage/Hashed/Tree.hs view
@@ -64,13 +64,15 @@ -- A Tree may have a Hash associated with it. A pair of Tree's is identical -- whenever their hashes are (the reverse need not hold, since not all Trees -- come equipped with a hash).-data Tree m = Tree { items :: M.Map Name (TreeItem m)-                   , listImmediate :: [(Name, TreeItem m)]+data Tree m = Tree { items :: (M.Map Name (TreeItem m))                    -- | Get hash of a Tree. This is guaranteed to uniquely                    -- identify the Tree (including any blob content), as far as                    -- cryptographic hashes are concerned. Sha256 is recommended.                    , treeHash :: !Hash } +listImmediate :: Tree m -> [(Name, TreeItem m)]+listImmediate = M.toList . items+ -- | Get a hash of a TreeItem. May be Nothing. itemHash :: TreeItem m -> Hash itemHash (File (Blob _ h)) = h@@ -84,7 +86,6 @@  emptyTree :: (Monad m) => Tree m emptyTree = Tree { items = M.empty-                 , listImmediate = []                  , treeHash = NoHash }  emptyBlob :: (Monad m) => Blob m@@ -98,12 +99,10 @@  makeTree :: (Monad m) => [(Name,TreeItem m)] -> Tree m makeTree l = Tree { items = M.fromList l-                  , listImmediate = l                   , treeHash = NoHash }  makeTreeWithHash :: (Monad m) => [(Name,TreeItem m)] -> Hash -> Tree m makeTreeWithHash l h = Tree { items = M.fromList l-                            , listImmediate = l                             , treeHash = h }  -----------------------------------@@ -157,8 +156,7 @@             let orig = [ i | i <- listImmediate t, not $ isSub $ snd i ]                 orig_map = M.filter (not . isSub) (items t)                 expanded_map = M.fromList expanded-                tree = t { items = M.union orig_map expanded_map-                         , listImmediate = orig ++ expanded }+                tree = t { items = M.union orig_map expanded_map }             update path tree           unstub (Stub s _) = s           unstub (SubTree t) = return t@@ -187,8 +185,7 @@           amend t name rest sub = do             sub' <- expand' sub (AnchoredPath rest)             let orig_l = [ i | i@(n',_) <- listImmediate t, name /= n' ]-                tree = t { items = M.insert name (SubTree sub') (items t)-                         , listImmediate = (name, SubTree sub') : orig_l }+                tree = t { items = M.insert name (SubTree sub') (items t) }             return tree  class (Monad m) => FilterTree a m where@@ -203,8 +200,7 @@         where filter' t path =                   let subs = (catMaybes [ (,) name `fmap` wibble path name item                                               | (name,item) <- listImmediate t ])-                  in t { items = M.mapMaybeWithKey (wibble path) $ items t-                       , listImmediate = subs }+                  in t { items = M.mapMaybeWithKey (wibble path) $ items t }               wibble path name item =                   let npath = path `appendPath` name in                       if predicate npath item@@ -324,33 +320,31 @@               is_r = [ (n, r) | (n, _, Just r) <- is ]           return (makeTree is_l, makeTree is_r) +-- | Modify a Tree (by replacing, or removing or adding items). modifyTree :: (Monad m) => Tree m -> AnchoredPath -> Maybe (TreeItem m) -> Tree m  modifyTree _ (AnchoredPath []) (Just (SubTree sub)) = sub  modifyTree t (AnchoredPath [n]) (Just item) =-    t { items = M.insert n item (items t)-      , listImmediate = (n,item) : subs+    t { items = countmap items' `seq` items'       , treeHash = NoHash }-  where subs = [ x | x@(n', _) <- listImmediate t, n /= n' ]+  where !items' = M.insert n item (items t)  modifyTree t (AnchoredPath [n]) Nothing =-    t { items = M.delete n (items t)-      , listImmediate = subs+    t { items = countmap items' `seq` items'       , treeHash = NoHash }-  where subs = [ x | x@(n', _) <- listImmediate t, n /= n' ]+  where !items' = M.delete n (items t)  modifyTree t path@(AnchoredPath (n:r)) item =-    t { items = M.insert n sub (items t)-      , listImmediate = (n,sub) : subs+    t { items = countmap items' `seq` items'       , treeHash = NoHash }-  where subs = [ x | x@(n', _) <- listImmediate t, n /= n' ]-        modSubtree s = modifyTree s (AnchoredPath r) item-        sub = case lookup t n of-                Just (SubTree s) -> SubTree $ modSubtree s+  where subtree s = modifyTree s (AnchoredPath r) item+        !items' = M.insert n sub (items t)+        !sub = case lookup t n of+                Just (SubTree s) -> SubTree $! subtree s                 Just (Stub s _) -> Stub (do x <- s-                                            return $ modSubtree x) NoHash-                Nothing -> SubTree $ modSubtree emptyTree+                                            return $! subtree x) NoHash+                Nothing -> SubTree $! subtree emptyTree                 _ -> error $ "Modify tree at " ++ show path  modifyTree _ (AnchoredPath []) (Just (Stub _ _)) =@@ -360,10 +354,11 @@ modifyTree _ (AnchoredPath []) Nothing =     error "Bug in descent in modifyTree." +countmap = M.fold (\_ i -> i + 1) 0+ updateSubtrees :: (Tree m -> Tree m) -> Tree m -> Tree m updateSubtrees fun t =     fun $ t { items = M.mapWithKey (curry $ snd . update) $ items t-            , listImmediate = map update $ listImmediate t             , treeHash = NoHash }   where update (k, SubTree s) = (k, SubTree $ updateSubtrees fun s)         update (k, File f) = (k, File f)@@ -374,7 +369,6 @@ updateTree fun t = do     immediate <- mapM update $ listImmediate t     SubTree t' <- fun . SubTree $ t { items = M.fromList immediate-                                    , listImmediate = immediate                                     , treeHash = NoHash }     return t'   where update (k, SubTree tree) = (\new -> (k, SubTree new)) <$> updateTree fun tree@@ -388,7 +382,6 @@ -- any extraneous items will be ignored by the implementation). overlay :: (Functor m, Monad m) => Tree m -> Tree m -> Tree m overlay base over = Tree { items = M.fromList immediate-                         , listImmediate = immediate                          , treeHash = NoHash }     where immediate = [ (n, get n) | (n, _) <- listImmediate base ]           get n = case (M.lookup n $ items base, M.lookup n $ items over) of
hashed-storage.cabal view
@@ -1,5 +1,5 @@ name:          hashed-storage-version:       0.4.6+version:       0.4.7 synopsis:      Hashed file storage support code.  description:   Support code for reading and manipulating hashed file storage