This commit is contained in:
voidlizard 2025-01-22 10:00:46 +03:00
parent 242101fd9c
commit b263bfbdc9
4 changed files with 105 additions and 56 deletions

View File

@ -1,5 +1,6 @@
{-# Language UndecidableInstances #-} {-# Language UndecidableInstances #-}
{-# Language AllowAmbiguousTypes #-} {-# Language AllowAmbiguousTypes #-}
{-# Language MultiWayIf #-}
module HBS2.Git3.Import where module HBS2.Git3.Import where
import HBS2.Git3.Prelude import HBS2.Git3.Prelude
@ -20,6 +21,7 @@ import Data.ByteString.Lazy qualified as LBS
import Data.ByteString qualified as BS import Data.ByteString qualified as BS
import Data.HashSet (HashSet) import Data.HashSet (HashSet)
import Data.HashSet qualified as HS import Data.HashSet qualified as HS
import Data.Maybe
import Data.List qualified as L import Data.List qualified as L
import Network.ByteOrder qualified as N import Network.ByteOrder qualified as N
import System.IO.Temp as Temp import System.IO.Temp as Temp
@ -105,6 +107,11 @@ writeAsGitPack dir href = do
pure Nothing pure Nothing
data ImportStage =
ImportStart
| ImportWIP Int (Maybe HashRef)
| ImportWait ImportStage
| ImportDone (Maybe HashRef)
importGitRefLog :: forall m . ( HBS2GitPerks m importGitRefLog :: forall m . ( HBS2GitPerks m
-- , HasStorage m -- , HasStorage m
@ -115,20 +122,42 @@ importGitRefLog :: forall m . ( HBS2GitPerks m
) )
=> Git3 m (Maybe HashRef) => Git3 m (Maybe HashRef)
importGitRefLog = withStateDo do importGitRefLog = withStateDo $ ask >>= \case
Git3Disconnected{} -> throwIO Git3PeerNotConnected
updateReflogIndex env@Git3Connected{..} -> do
packs <- gitDir packs <- gitDir
>>= orThrowUser "git directory not found" >>= orThrow NoGitDir
<&> (</> "objects/pack") <&> (</> "objects/pack")
mkdir packs mkdir packs
sto <- getStorage sto <- getStorage
flip fix ImportStart $ \again -> \case
ImportDone x -> pure x
ImportWait next -> do
notice "wait some time..."
pause @'Seconds 3
again next
ImportStart -> do
rvl <- readTVarIO gitRefLogVal
prev <- importedCheckpoint prev <- importedCheckpoint
if | isNothing prev -> again $ ImportWIP 0 prev
| prev /= rvl -> do
again $ ImportWIP 0 prev
| otherwise -> again $ ImportDone prev
ImportWIP attempt prev -> do
updateReflogIndex
excl <- maybe1 prev (pure mempty) $ \p -> do excl <- maybe1 prev (pure mempty) $ \p -> do
txListAll (Just p) <&> HS.fromList . fmap fst txListAll (Just p) <&> HS.fromList . fmap fst
@ -155,12 +184,14 @@ importGitRefLog = withStateDo do
else do else do
next (xs, l) next (xs, l)
runMaybeT do case cp' of
cp <- toMPlus cp' Nothing -> again $ ImportDone Nothing
notice $ "found checkpoint" <+> pretty cp Just cp -> do
txs <- lift $ txList ( pure . not . flip HS.member excl ) (Just cp)
lift do notice $ "found checkpoint" <+> pretty cp
txs <- txList ( pure . not . flip HS.member excl ) (Just cp)
r <- liftIO $ try @_ @SomeException $ withGit3Env env do
forConcurrently_ txs $ \case forConcurrently_ txs $ \case
(_, TxCheckpoint{}) -> none (_, TxCheckpoint{}) -> none
(h, TxSegment tree) -> do (h, TxSegment tree) -> do
@ -174,5 +205,11 @@ importGitRefLog = withStateDo do
updateImportedCheckpoint cp updateImportedCheckpoint cp
pure cp case r of
Right _ -> again $ ImportDone (Just cp)
Left e -> do
case (fromException e :: Maybe OperationError) of
Just (MissedBlockError2 _) -> again $ ImportWait (ImportWIP (succ attempt) prev)
Just MissedBlockError -> again $ ImportWait (ImportWIP (succ attempt) prev)
_ -> throwIO e

View File

@ -486,5 +486,12 @@ repo:key ; shows current repo key
entry $ bindMatch "repo:init" $ nil_ $ \syn -> lift $ connectedDo do entry $ bindMatch "repo:init" $ nil_ $ \syn -> lift $ connectedDo do
Repo.initRepo syn Repo.initRepo syn
entry $ bindMatch "repo:relay-only" $ nil_ $ \case
[ SignPubKeyLike repo ] -> lift $ connectedDo do
setGitRepoKey repo
waitRepo (Just 2)
_ -> throwIO (BadFormException @C nil)
exportEntries "reflog:" exportEntries "reflog:"

View File

@ -43,6 +43,7 @@ import System.TimeIt
import Lens.Micro.Platform import Lens.Micro.Platform
import Control.Concurrent.STM qualified as STM import Control.Concurrent.STM qualified as STM
import Control.Exception qualified as E
import UnliftIO.IO.File qualified as UIO import UnliftIO.IO.File qualified as UIO
@ -305,7 +306,7 @@ updateReflogIndex = do
flip runContT pure do flip runContT pure do
what' <- lift $ callRpcWaitMay @RpcRefLogGet (TimeoutSec 2) api reflog what' <- lift $ callRpcWaitMay @RpcRefLogGet (TimeoutSec 2) api reflog
>>= orThrow Git3RpcTimeout >>= orThrow RpcTimeout
what <- ContT $ maybe1 what' none what <- ContT $ maybe1 what' none
@ -437,7 +438,7 @@ trimRefs = do
mapM_ rm files mapM_ rm files
importedCheckpoint :: forall m . ( Git3Perks m importedCheckpoint :: forall m . ( MonadIO m
, MonadReader Git3Env m , MonadReader Git3Env m
, HasClientAPI RefLogAPI UNIX m , HasClientAPI RefLogAPI UNIX m
, HasStorage m , HasStorage m
@ -448,7 +449,7 @@ importedCheckpoint = do
state <- getStatePathM state <- getStatePathM
let imported = state </> "imported" let imported = state </> "imported"
runMaybeT do runMaybeT do
f <- liftIO (try @_ @IOError (readFile imported <&> headMay . lines)) f <- liftIO (E.try @IOError (readFile imported <&> headMay . lines))
>>= toMPlus >>= toMPlus
>>= toMPlus >>= toMPlus
@ -484,7 +485,7 @@ readRefsRaw :: forall m . ( Git3Perks m
=> [FilePath] -> m [Syntax C] => [FilePath] -> m [Syntax C]
readRefsRaw files = do readRefsRaw files = do
mapM (try @_ @IOError . liftIO . readFile) files mapM (liftIO . E.try @IOError . readFile) files
<&> unlines . rights <&> unlines . rights
<&> parseTop <&> parseTop
<&> fromRight mempty <&> fromRight mempty

View File

@ -55,6 +55,9 @@ data HBS2GitExcepion =
| RefLogCredentialsNotMatched | RefLogCredentialsNotMatched
| RefLogNotReady | RefLogNotReady
| RpcTimeout | RpcTimeout
| Git3PeerNotConnected
| Git3ReflogNotSet
| NoGitDir
deriving stock (Show,Typeable) deriving stock (Show,Typeable)
instance Exception HBS2GitExcepion instance Exception HBS2GitExcepion
@ -86,14 +89,6 @@ instance Hashable GitWritePacksOptVal
instance GitWritePacksOpts (HashSet GitWritePacksOptVal) where instance GitWritePacksOpts (HashSet GitWritePacksOptVal) where
excludeParents o = not $ HS.member WriteFullPack o excludeParents o = not $ HS.member WriteFullPack o
data Git3Exception =
Git3PeerNotConnected
| Git3ReflogNotSet
| Git3RpcTimeout
deriving (Show,Typeable,Generic)
instance Exception Git3Exception
data Git3Env = data Git3Env =
Git3Disconnected Git3Disconnected
{ gitPackedSegmentSize :: TVar Int { gitPackedSegmentSize :: TVar Int
@ -170,6 +165,10 @@ instance (MonadIO m) => HasGitRemoteKey (Git3 m) where
e <- ask e <- ask
liftIO $ atomically $ writeTVar (gitRepoKey e) (Just k) liftIO $ atomically $ writeTVar (gitRepoKey e) (Just k)
instance (MonadIO m, HasGitRemoteKey (Git3 m)) => HasGitRemoteKey (ContT whatever (Git3 m)) where
getGitRemoteKey = lift getGitRemoteKey
getGitRepoKey = lift getGitRepoKey
setGitRepoKey = lift . setGitRepoKey
newtype Git3 (m :: Type -> Type) a = Git3M { fromGit3 :: ReaderT Git3Env m a } newtype Git3 (m :: Type -> Type) a = Git3M { fromGit3 :: ReaderT Git3Env m a }
deriving newtype ( Applicative deriving newtype ( Applicative
@ -185,7 +184,6 @@ type Git3Perks m = ( MonadIO m
, MonadUnliftIO m , MonadUnliftIO m
) )
instance MonadUnliftIO m => HasClientAPI PeerAPI UNIX (Git3 m) where instance MonadUnliftIO m => HasClientAPI PeerAPI UNIX (Git3 m) where
getClientAPI = do getClientAPI = do
ask >>= \case ask >>= \case
@ -205,7 +203,13 @@ instance (MonadUnliftIO m) => HasClientAPI LWWRefAPI UNIX (Git3 m) where
Git3Disconnected{} -> throwIO Git3PeerNotConnected Git3Disconnected{} -> throwIO Git3PeerNotConnected
Git3Connected{..} -> pure lwwAPI Git3Connected{..} -> pure lwwAPI
getStatePathM :: forall m . (HBS2GitPerks m, HasGitRemoteKey m) => m FilePath instance HasClientAPI api UNIX (Git3 m) => HasClientAPI api UNIX (ContT whatever (Git3 m)) where
getClientAPI = lift (getClientAPI @api @UNIX)
instance HasClientAPI api UNIX (Git3 m) => HasClientAPI api UNIX (MaybeT (Git3 m)) where
getClientAPI = lift getClientAPI
getStatePathM :: forall m . (MonadIO m, HasGitRemoteKey m) => m FilePath
getStatePathM = do getStatePathM = do
k <- getGitRemoteKey >>= orThrow RefLogNotSet k <- getGitRemoteKey >>= orThrow RefLogNotSet
getStatePath (AsBase58 k) >>= orThrow StateDirNotDefined getStatePath (AsBase58 k) >>= orThrow StateDirNotDefined