rolling total of size changes in RepoSize database

When a live size change completes successfully, the same transaction
that removes it from the database updates the rolling total for its
repository.

The idea is that when RepoSizes is read, SizeChanges will be as
well, and cached locally. Any time a change is made, the local cache
will be updated. So by comparing the local cache with the current
SizeChanges, it can learn about size changes that were made by other
processes. Then read the LiveSizeChanges, and add that in to get a live
picture of the current sizes.

Also added a SizeChangeId. This allows 2 different threads, or
processes, to both record a live size change for the same repo and key,
and update their own information without stepping on one-another's toes.
This commit is contained in:
Joey Hess 2024-08-25 10:34:47 -04:00
parent 9188825a4d
commit 18f8d61f55
No known key found for this signature in database
GPG key ID: DB12DB0FF05F8F38
3 changed files with 128 additions and 30 deletions

View file

@ -27,7 +27,9 @@ module Database.RepoSize (
setRepoSizes,
getLiveSizeChanges,
startingLiveSizeChange,
finishedLiveSizeChange,
successfullyFinishedLiveSizeChange,
staleLiveSizeChange,
getSizeChanges,
) where
import Annex.Common
@ -57,11 +59,20 @@ AnnexBranch
commit SSha
UniqueCommit commit
-- Changes that are currently being made that affect repo sizes.
-- (Only updated when preferred content expressions are in use that need
-- live size changes.)
LiveSizeChanges
repo UUID
key Key
changeid SizeChangeId
change SizeChange
UniqueLiveSizeChange repo key
UniqueLiveSizeChange repo key changeid
-- A rolling total of size changes that were removed from LiveSizeChanges
-- upon successful completion.
SizeChanges
repo UUID
rollingtotal FileSize
UniqueRepoRollingTotal repo
|]
{- Gets a handle to the database. It's cached in Annex state. -}
@ -162,34 +173,81 @@ recordAnnexBranchCommit branchcommitsha = do
deleteWhere ([] :: [Filter AnnexBranch])
void $ insertUniqueFast $ AnnexBranch $ toSSha branchcommitsha
{- If there is already a size change for the same UUID and Key, it is
- overwritten with the new size change. -}
startingLiveSizeChange :: RepoSizeHandle -> UUID -> Key -> SizeChange -> IO ()
startingLiveSizeChange (RepoSizeHandle (Just h)) u k sc =
{- If there is already a size change for the same UUID, Key,
- and SizeChangeId, it is overwritten with the new size change. -}
startingLiveSizeChange :: RepoSizeHandle -> UUID -> Key -> SizeChange -> SizeChangeId -> IO ()
startingLiveSizeChange (RepoSizeHandle (Just h)) u k sc sid =
H.commitDb h $ void $ upsertBy
(UniqueLiveSizeChange u k)
(LiveSizeChanges u k sc)
[LiveSizeChangesChange =. sc]
startingLiveSizeChange (RepoSizeHandle Nothing) _ _ _ = noop
(UniqueLiveSizeChange u k sid)
(LiveSizeChanges u k sid sc)
[ LiveSizeChangesChange =. sc
, LiveSizeChangesChangeid =. sid
]
startingLiveSizeChange (RepoSizeHandle Nothing) _ _ _ _ = noop
finishedLiveSizeChange :: RepoSizeHandle -> UUID -> Key -> SizeChange -> IO ()
finishedLiveSizeChange (RepoSizeHandle (Just h)) u k sc =
H.commitDb h $ deleteWhere
successfullyFinishedLiveSizeChange :: RepoSizeHandle -> UUID -> Key -> SizeChange -> SizeChangeId -> IO ()
successfullyFinishedLiveSizeChange (RepoSizeHandle (Just h)) u k sc sid =
H.commitDb h $ do
-- Update the rolling total and remove the live change in the
-- same transaction.
rollingtotal <- getSizeChangeFor u
setSizeChangeFor u (updaterollingtotal rollingtotal)
removeLiveSizeChange u k sc sid
where
updaterollingtotal t = case sc of
AddingKey -> t + ksz
RemovingKey -> t - ksz
ksz = fromMaybe 0 $ fromKey keySize k
successfullyFinishedLiveSizeChange (RepoSizeHandle Nothing) _ _ _ _ = noop
staleLiveSizeChange :: RepoSizeHandle -> UUID -> Key -> SizeChange -> SizeChangeId -> IO ()
staleLiveSizeChange (RepoSizeHandle (Just h)) u k sc sid =
H.commitDb h $ removeLiveSizeChange u k sc sid
staleLiveSizeChange (RepoSizeHandle Nothing) _ _ _ _ = noop
removeLiveSizeChange :: UUID -> Key -> SizeChange -> SizeChangeId -> SqlPersistM ()
removeLiveSizeChange u k sc sid =
deleteWhere
[ LiveSizeChangesRepo ==. u
, LiveSizeChangesKey ==. k
, LiveSizeChangesChangeid ==. sid
, LiveSizeChangesChange ==. sc
]
finishedLiveSizeChange (RepoSizeHandle Nothing) _ _ _ = noop
getLiveSizeChanges :: RepoSizeHandle -> IO (M.Map UUID (Key, SizeChange))
getLiveSizeChanges :: RepoSizeHandle -> IO (M.Map UUID (Key, SizeChange, SizeChangeId))
getLiveSizeChanges (RepoSizeHandle (Just h)) = H.queryDb h $ do
m <- M.fromList . map conv <$> getLiveSizeChanges'
return m
where
conv entity =
let LiveSizeChanges u k sc = entityVal entity
in (u, (k, sc))
let LiveSizeChanges u k sid sc = entityVal entity
in (u, (k, sc, sid))
getLiveSizeChanges (RepoSizeHandle Nothing) = return mempty
getLiveSizeChanges' :: SqlPersistM [Entity LiveSizeChanges]
getLiveSizeChanges' = selectList [] []
getSizeChanges :: RepoSizeHandle -> IO (M.Map UUID FileSize)
getSizeChanges (RepoSizeHandle (Just h)) = H.queryDb h getSizeChanges'
getSizeChanges (RepoSizeHandle Nothing) = return mempty
getSizeChanges' :: SqlPersistM (M.Map UUID FileSize)
getSizeChanges' = M.fromList . map conv <$> selectList [] []
where
conv entity =
let SizeChanges u n = entityVal entity
in (u, n)
getSizeChangeFor :: UUID -> SqlPersistM FileSize
getSizeChangeFor u = do
l <- selectList [SizeChangesRepo ==. u] []
return $ case l of
(s:_) -> sizeChangesRollingtotal $ entityVal s
[] -> 0
setSizeChangeFor :: UUID -> FileSize -> SqlPersistM ()
setSizeChangeFor u sz =
void $ upsertBy
(UniqueRepoRollingTotal u)
(SizeChanges u sz)
[SizeChangesRollingtotal =. sz]