2024-08-13 15:00:20 +00:00
|
|
|
{- git-annex repo sizes
|
|
|
|
-
|
|
|
|
- Copyright 2024 Joey Hess <id@joeyh.name>
|
|
|
|
-
|
|
|
|
- Licensed under the GNU AGPL version 3 or higher.
|
|
|
|
-}
|
|
|
|
|
2024-08-16 14:56:51 +00:00
|
|
|
{-# LANGUAGE OverloadedStrings, BangPatterns #-}
|
2024-08-15 16:40:48 +00:00
|
|
|
|
2024-08-15 16:31:56 +00:00
|
|
|
module Annex.RepoSize (
|
|
|
|
getRepoSizes,
|
2024-08-27 14:17:43 +00:00
|
|
|
getLiveRepoSizes,
|
2024-08-15 16:31:56 +00:00
|
|
|
) where
|
2024-08-13 15:00:20 +00:00
|
|
|
|
|
|
|
import Annex.Common
|
2024-08-15 17:27:14 +00:00
|
|
|
import Annex.RepoSize.LiveUpdate
|
2024-08-15 16:31:56 +00:00
|
|
|
import qualified Annex
|
|
|
|
import Annex.Branch (UnmergedBranches(..), getBranch)
|
|
|
|
import qualified Database.RepoSize as Db
|
2024-08-17 17:30:24 +00:00
|
|
|
import Logs
|
2024-08-13 15:00:20 +00:00
|
|
|
import Logs.Location
|
|
|
|
import Logs.UUID
|
2024-08-14 07:19:30 +00:00
|
|
|
import Git.Types (Sha)
|
2024-08-17 17:30:24 +00:00
|
|
|
import Git.FilePath
|
|
|
|
import Git.CatFile
|
|
|
|
import qualified Git.DiffTree as DiffTree
|
2024-08-13 15:00:20 +00:00
|
|
|
|
2024-08-16 14:56:51 +00:00
|
|
|
import Control.Concurrent
|
2024-08-17 17:30:24 +00:00
|
|
|
import Control.Concurrent.Async
|
2024-08-13 15:00:20 +00:00
|
|
|
import qualified Data.Map.Strict as M
|
2024-08-17 17:30:24 +00:00
|
|
|
import qualified Data.Set as S
|
2024-08-13 15:00:20 +00:00
|
|
|
|
2024-08-27 14:17:43 +00:00
|
|
|
{- Gets the repo size map. Cached for speed.
|
|
|
|
-
|
|
|
|
- Note that this is the size of all repositories as of the first time it
|
|
|
|
- was called. It does not update while git-annex is running.
|
|
|
|
-}
|
2024-08-17 18:54:31 +00:00
|
|
|
getRepoSizes :: Bool -> Annex (M.Map UUID RepoSize)
|
|
|
|
getRepoSizes quiet = do
|
2024-08-16 14:56:51 +00:00
|
|
|
rsv <- Annex.getRead Annex.reposizes
|
|
|
|
liftIO (takeMVar rsv) >>= \case
|
|
|
|
Just sizemap -> do
|
|
|
|
liftIO $ putMVar rsv (Just sizemap)
|
|
|
|
return sizemap
|
2024-08-17 18:54:31 +00:00
|
|
|
Nothing -> calcRepoSizes quiet rsv
|
2024-08-15 16:31:56 +00:00
|
|
|
|
2024-08-27 14:17:43 +00:00
|
|
|
{- Like getRepoSizes, but with live updates. -}
|
|
|
|
getLiveRepoSizes :: Bool -> Annex (M.Map UUID RepoSize)
|
|
|
|
getLiveRepoSizes quiet = do
|
|
|
|
h <- Db.getRepoSizeHandle
|
|
|
|
liftIO (Db.estimateLiveRepoSizes h) >>= \case
|
|
|
|
Just (m, annexbranchsha) -> return m
|
|
|
|
Nothing -> do
|
|
|
|
-- Db.estimateLiveRepoSizes needs the
|
|
|
|
-- reposizes to be calculated first.
|
|
|
|
m <- getRepoSizes quiet
|
|
|
|
liftIO (Db.estimateLiveRepoSizes h) >>= \case
|
|
|
|
Just (m', annexbranchsha) -> return m'
|
|
|
|
Nothing -> return m
|
|
|
|
|
2024-08-16 14:56:51 +00:00
|
|
|
{- Fills an empty Annex.reposizes MVar with current information
|
|
|
|
- from the git-annex branch, supplimented with journalled but
|
|
|
|
- not yet committed information.
|
2024-08-15 16:31:56 +00:00
|
|
|
-}
|
2024-08-17 18:54:31 +00:00
|
|
|
calcRepoSizes :: Bool -> MVar (Maybe (M.Map UUID RepoSize)) -> Annex (M.Map UUID RepoSize)
|
2024-08-27 14:17:43 +00:00
|
|
|
calcRepoSizes quiet rsv = go `onException` failed
|
2024-08-15 16:31:56 +00:00
|
|
|
where
|
2024-08-27 14:17:43 +00:00
|
|
|
go = do
|
|
|
|
h <- Db.getRepoSizeHandle
|
2024-08-16 14:56:51 +00:00
|
|
|
(oldsizemap, moldbranchsha) <- liftIO $ Db.getRepoSizes h
|
|
|
|
!sizemap <- case moldbranchsha of
|
|
|
|
Nothing -> calculatefromscratch h
|
|
|
|
Just oldbranchsha -> do
|
|
|
|
currbranchsha <- getBranch
|
|
|
|
if oldbranchsha == currbranchsha
|
|
|
|
then calcJournalledRepoSizes oldsizemap oldbranchsha
|
2024-08-17 17:30:24 +00:00
|
|
|
else incrementalupdate h oldsizemap oldbranchsha currbranchsha
|
2024-08-16 14:56:51 +00:00
|
|
|
liftIO $ putMVar rsv (Just sizemap)
|
|
|
|
return sizemap
|
|
|
|
|
2024-08-15 16:31:56 +00:00
|
|
|
calculatefromscratch h = do
|
2024-08-17 18:54:31 +00:00
|
|
|
unless quiet $
|
|
|
|
showSideAction "calculating repository sizes"
|
2024-08-15 16:31:56 +00:00
|
|
|
(sizemap, branchsha) <- calcBranchRepoSizes
|
|
|
|
liftIO $ Db.setRepoSizes h sizemap branchsha
|
2024-08-15 17:37:41 +00:00
|
|
|
calcJournalledRepoSizes sizemap branchsha
|
2024-08-16 14:56:51 +00:00
|
|
|
|
2024-08-17 17:30:24 +00:00
|
|
|
incrementalupdate h oldsizemap oldbranchsha currbranchsha = do
|
2024-08-17 18:54:31 +00:00
|
|
|
(sizemap, branchsha) <- diffBranchRepoSizes quiet oldsizemap oldbranchsha currbranchsha
|
2024-08-17 17:30:24 +00:00
|
|
|
liftIO $ Db.setRepoSizes h sizemap branchsha
|
|
|
|
calcJournalledRepoSizes sizemap branchsha
|
|
|
|
|
2024-08-16 14:56:51 +00:00
|
|
|
failed = do
|
|
|
|
liftIO $ putMVar rsv (Just M.empty)
|
|
|
|
return M.empty
|
2024-08-15 16:31:56 +00:00
|
|
|
|
2024-08-13 15:00:20 +00:00
|
|
|
{- Sum up the sizes of all keys in all repositories, from the information
|
2024-08-14 07:19:30 +00:00
|
|
|
- in the git-annex branch, but not the journal. Retuns the sha of the
|
|
|
|
- branch commit that was used.
|
2024-08-13 15:00:20 +00:00
|
|
|
-
|
|
|
|
- The map includes the UUIDs of all known repositories, including
|
2024-08-17 17:30:24 +00:00
|
|
|
- repositories that are empty. But clusters are not included.
|
2024-08-14 17:46:44 +00:00
|
|
|
-
|
|
|
|
- Note that private repositories, which do not get recorded in
|
|
|
|
- the git-annex branch, will have 0 size. journalledRepoSizes
|
|
|
|
- takes care of getting repo sizes for those.
|
2024-08-13 15:00:20 +00:00
|
|
|
-}
|
2024-08-14 07:19:30 +00:00
|
|
|
calcBranchRepoSizes :: Annex (M.Map UUID RepoSize, Sha)
|
|
|
|
calcBranchRepoSizes = do
|
2024-08-13 15:00:20 +00:00
|
|
|
knownuuids <- M.keys <$> uuidDescMap
|
|
|
|
let startmap = M.fromList $ map (\u -> (u, RepoSize 0)) knownuuids
|
2024-08-17 15:16:21 +00:00
|
|
|
overLocationLogs True True startmap accumsizes >>= \case
|
2024-08-14 07:19:30 +00:00
|
|
|
UnmergedBranches v -> return v
|
|
|
|
NoUnmergedBranches v -> return v
|
2024-08-13 15:00:20 +00:00
|
|
|
where
|
2024-08-14 17:46:44 +00:00
|
|
|
accumsizes k locs m = return $
|
|
|
|
foldl' (flip $ M.alter $ addKeyRepoSize k) m locs
|
2024-08-14 07:19:30 +00:00
|
|
|
|
|
|
|
{- Given the RepoSizes calculated from the git-annex branch, updates it with
|
|
|
|
- data from journalled location logs.
|
|
|
|
-}
|
2024-08-16 14:56:51 +00:00
|
|
|
calcJournalledRepoSizes
|
|
|
|
:: M.Map UUID RepoSize
|
|
|
|
-> Sha
|
|
|
|
-> Annex (M.Map UUID RepoSize)
|
|
|
|
calcJournalledRepoSizes startmap branchsha =
|
2024-08-17 17:30:24 +00:00
|
|
|
overLocationLogsJournal startmap branchsha
|
|
|
|
(\k v m -> pure (accumRepoSizes k v m))
|
|
|
|
Nothing
|
|
|
|
|
|
|
|
{- Incremental update by diffing. -}
|
2024-08-17 18:54:31 +00:00
|
|
|
diffBranchRepoSizes :: Bool -> M.Map UUID RepoSize -> Sha -> Sha -> Annex (M.Map UUID RepoSize, Sha)
|
|
|
|
diffBranchRepoSizes quiet oldsizemap oldbranchsha newbranchsha = do
|
2024-08-17 17:30:24 +00:00
|
|
|
g <- Annex.gitRepo
|
|
|
|
catObjectStream g $ \feeder closer reader -> do
|
|
|
|
(l, cleanup) <- inRepo $
|
|
|
|
DiffTree.diffTreeRecursive oldbranchsha newbranchsha
|
|
|
|
feedtid <- liftIO $ async $ do
|
|
|
|
forM_ l $ feedpairs feeder
|
|
|
|
closer
|
2024-08-17 19:59:07 +00:00
|
|
|
newsizemap <- readpairs 100000 reader oldsizemap Nothing
|
2024-08-17 17:30:24 +00:00
|
|
|
liftIO $ wait feedtid
|
|
|
|
ifM (liftIO cleanup)
|
2024-08-22 11:03:22 +00:00
|
|
|
( do
|
|
|
|
newsizemap' <- addemptyrepos newsizemap
|
|
|
|
return (newsizemap', newbranchsha)
|
2024-08-17 17:30:24 +00:00
|
|
|
, return (oldsizemap, oldbranchsha)
|
|
|
|
)
|
2024-08-14 17:46:44 +00:00
|
|
|
where
|
2024-08-17 17:30:24 +00:00
|
|
|
feedpairs feeder ti =
|
|
|
|
let f = getTopFilePath (DiffTree.file ti)
|
|
|
|
in case extLogFileKey locationLogExt f of
|
|
|
|
Nothing -> noop
|
|
|
|
Just k -> do
|
|
|
|
feeder (k, DiffTree.srcsha ti)
|
|
|
|
feeder (k, DiffTree.dstsha ti)
|
|
|
|
|
|
|
|
readpairs n reader sizemap Nothing = liftIO reader >>= \case
|
|
|
|
Just (_k, oldcontent) -> readpairs n reader sizemap (Just oldcontent)
|
|
|
|
Nothing -> return sizemap
|
|
|
|
readpairs n reader sizemap (Just oldcontent) = liftIO reader >>= \case
|
|
|
|
Just (k, newcontent) ->
|
|
|
|
let prevlog = parselog oldcontent
|
|
|
|
currlog = parselog newcontent
|
|
|
|
newlocs = S.difference currlog prevlog
|
|
|
|
removedlocs = S.difference prevlog currlog
|
|
|
|
!sizemap' = accumRepoSizes k (newlocs, removedlocs) sizemap
|
|
|
|
in do
|
2024-08-17 18:54:31 +00:00
|
|
|
n' <- if quiet
|
|
|
|
then pure n
|
|
|
|
else countdownToMessage n $
|
|
|
|
showSideAction "calculating repository sizes"
|
2024-08-17 17:30:24 +00:00
|
|
|
readpairs n' reader sizemap' Nothing
|
|
|
|
Nothing -> return sizemap
|
|
|
|
parselog = maybe mempty (S.fromList . parseLoggedLocationsWithoutClusters)
|
2024-08-22 11:03:22 +00:00
|
|
|
|
|
|
|
addemptyrepos newsizemap = do
|
|
|
|
knownuuids <- M.keys <$> uuidDescMap
|
|
|
|
return $ foldl'
|
|
|
|
(\m u -> M.insertWith (flip const) u (RepoSize 0) m)
|
|
|
|
newsizemap
|
|
|
|
knownuuids
|