mirror of https://github.com/voidlizard/hbs2
NCQv1 -> NCQ3 migration
This commit is contained in:
parent
500ad351a5
commit
2a1260ac97
|
@ -16,6 +16,7 @@ import HBS2.CLI.Run.RefLog
|
||||||
import HBS2.CLI.Run.RefChan
|
import HBS2.CLI.Run.RefChan
|
||||||
import HBS2.CLI.Run.LWWRef
|
import HBS2.CLI.Run.LWWRef
|
||||||
import HBS2.CLI.Run.Mailbox
|
import HBS2.CLI.Run.Mailbox
|
||||||
|
import HBS2.CLI.NCQ3.Migrate
|
||||||
|
|
||||||
import Data.Config.Suckless.Script.File as SF
|
import Data.Config.Suckless.Script.File as SF
|
||||||
|
|
||||||
|
@ -37,6 +38,7 @@ setupLogger = do
|
||||||
setLogging @ERROR $ toStderr . logPrefix "[error] "
|
setLogging @ERROR $ toStderr . logPrefix "[error] "
|
||||||
setLogging @WARN $ toStderr . logPrefix "[warn] "
|
setLogging @WARN $ toStderr . logPrefix "[warn] "
|
||||||
setLogging @NOTICE $ toStderr . logPrefix ""
|
setLogging @NOTICE $ toStderr . logPrefix ""
|
||||||
|
setLogging @INFO $ toStderr . logPrefix ""
|
||||||
pure ()
|
pure ()
|
||||||
|
|
||||||
flushLoggers :: MonadIO m => m ()
|
flushLoggers :: MonadIO m => m ()
|
||||||
|
@ -79,6 +81,7 @@ main = do
|
||||||
refchanEntries
|
refchanEntries
|
||||||
lwwRefEntries
|
lwwRefEntries
|
||||||
mailboxEntries
|
mailboxEntries
|
||||||
|
migrateEntries
|
||||||
helpEntries
|
helpEntries
|
||||||
|
|
||||||
SF.entries
|
SF.entries
|
||||||
|
|
|
@ -57,6 +57,7 @@ common shared-properties
|
||||||
hbs2-core
|
hbs2-core
|
||||||
, hbs2-peer
|
, hbs2-peer
|
||||||
, hbs2-storage-simple
|
, hbs2-storage-simple
|
||||||
|
, hbs2-storage-ncq
|
||||||
, hbs2-keyman-direct-lib
|
, hbs2-keyman-direct-lib
|
||||||
, db-pipe
|
, db-pipe
|
||||||
, suckless-conf
|
, suckless-conf
|
||||||
|
@ -124,6 +125,7 @@ library
|
||||||
HBS2.CLI.Run.Sigil
|
HBS2.CLI.Run.Sigil
|
||||||
|
|
||||||
HBS2.CLI.Run.Help
|
HBS2.CLI.Run.Help
|
||||||
|
HBS2.CLI.NCQ3.Migrate
|
||||||
|
|
||||||
build-depends: base
|
build-depends: base
|
||||||
, magic
|
, magic
|
||||||
|
|
|
@ -0,0 +1,165 @@
|
||||||
|
{-# Language AllowAmbiguousTypes #-}
|
||||||
|
module HBS2.CLI.NCQ3.Migrate where
|
||||||
|
|
||||||
|
import HBS2.CLI.Prelude
|
||||||
|
import HBS2.CLI.Run.Internal
|
||||||
|
|
||||||
|
import HBS2.Base58
|
||||||
|
import HBS2.Data.Types.Refs
|
||||||
|
import HBS2.Hash
|
||||||
|
import HBS2.Net.Auth.Schema()
|
||||||
|
import HBS2.Peer.CLI.Detect
|
||||||
|
import HBS2.Peer.RPC.API.LWWRef
|
||||||
|
import HBS2.Peer.RPC.API.Peer
|
||||||
|
import HBS2.Peer.RPC.API.RefLog
|
||||||
|
import HBS2.Peer.RPC.API.Storage
|
||||||
|
import HBS2.Peer.RPC.Client
|
||||||
|
import HBS2.Peer.RPC.Client.Unix
|
||||||
|
import HBS2.Storage
|
||||||
|
import HBS2.Storage.NCQ3
|
||||||
|
import HBS2.Storage.NCQ3.Internal.Files
|
||||||
|
import HBS2.Storage.NCQ3.Internal.Fossil
|
||||||
|
import HBS2.Storage.NCQ3.Internal.Index
|
||||||
|
import HBS2.Storage.NCQ3.Internal.Prelude
|
||||||
|
import HBS2.Peer.Proto.RefLog
|
||||||
|
import HBS2.Peer.Proto.RefChan
|
||||||
|
import HBS2.Peer.Proto.LWWRef
|
||||||
|
|
||||||
|
import Data.Config.Suckless.System
|
||||||
|
|
||||||
|
import Data.ByteString.Lazy qualified as LBS
|
||||||
|
import Data.ByteString qualified as BS
|
||||||
|
import Control.Monad.Trans.Cont
|
||||||
|
import Control.Monad.Trans.Maybe
|
||||||
|
import Data.HashSet (HashSet)
|
||||||
|
import Data.HashSet qualified as HS
|
||||||
|
import Data.Either
|
||||||
|
import Data.List qualified as L
|
||||||
|
import System.Directory (getModificationTime)
|
||||||
|
import UnliftIO.IO
|
||||||
|
|
||||||
|
import Streaming.Prelude qualified as S
|
||||||
|
|
||||||
|
{- HLINT ignore "Functor law"-}
|
||||||
|
|
||||||
|
data SomeRef = forall a . (Hashed HbSync a, Pretty a, RefMetaData a) => SomeRef a
|
||||||
|
|
||||||
|
instance RefMetaData SomeRef where
|
||||||
|
refMetaData (SomeRef a) = refMetaData a
|
||||||
|
|
||||||
|
instance Pretty SomeRef where
|
||||||
|
pretty (SomeRef wtf) = pretty wtf
|
||||||
|
|
||||||
|
instance Hashed HbSync SomeRef where
|
||||||
|
hashObject (SomeRef a) = hashObject a
|
||||||
|
|
||||||
|
legacyHashRefNCQ1 :: HashRef -> HashRef -> HashRef
|
||||||
|
legacyHashRefNCQ1 salt h = HashRef (hashObject (coerce @_ @ByteString h <> coerce salt))
|
||||||
|
|
||||||
|
legacyHashRefFor :: Hashed HbSync p => HashRef -> p -> HashRef
|
||||||
|
legacyHashRefFor salt x = legacyHashRefNCQ1 salt (HashRef $ hashObject @HbSync $ x)
|
||||||
|
|
||||||
|
migrateEntries :: forall c m . ( MonadUnliftIO m
|
||||||
|
, IsContext c
|
||||||
|
, Exception (BadFormException c)
|
||||||
|
, HasClientAPI PeerAPI UNIX m
|
||||||
|
, HasStorage m
|
||||||
|
) => MakeDictM c m ()
|
||||||
|
migrateEntries = do
|
||||||
|
brief "migrate NCQv1 => NCQ3"
|
||||||
|
$ args [ arg "path" "src"
|
||||||
|
, arg "path" "dst"
|
||||||
|
]
|
||||||
|
|
||||||
|
$ entry $ bindMatch "ncq3:migrate:ncq" $ nil_ $ \case
|
||||||
|
[ StringLike src, StringLike dst] -> do
|
||||||
|
|
||||||
|
sto <- getStorage
|
||||||
|
|
||||||
|
let a0 = src </> "0"
|
||||||
|
a0here <- doesPathExist a0
|
||||||
|
|
||||||
|
let a = if a0here then a0 else src
|
||||||
|
|
||||||
|
ncqSalt <- liftIO (try @_ @IOException (BS.readFile (a </> ".seed")))
|
||||||
|
<&> fromRight mempty
|
||||||
|
<&> HashRef . hashObject
|
||||||
|
|
||||||
|
api <- getClientAPI @PeerAPI @UNIX
|
||||||
|
|
||||||
|
refs <- callRpcWaitMay @RpcPollList2 (1.0 :: Timeout 'Seconds) api (Nothing, Nothing)
|
||||||
|
<&> fromMaybe mempty
|
||||||
|
|
||||||
|
rrefs <- S.toList_ <$> for refs $ \(pk, s, _) -> case s of
|
||||||
|
"reflog" -> S.yield (SomeRef $ RefLogKey @'HBS2Basic pk)
|
||||||
|
"refchan" -> S.yield (SomeRef $ RefChanLogKey @'HBS2Basic pk)
|
||||||
|
"lwwref" -> S.yield (SomeRef $ LWWRefKey @'HBS2Basic pk)
|
||||||
|
_ -> none
|
||||||
|
|
||||||
|
lift $ migrateNCQ1 nicelog sto rrefs a dst
|
||||||
|
|
||||||
|
e -> throwIO $ BadFormException (mkList e)
|
||||||
|
|
||||||
|
nicelog :: forall m . MonadIO m => Doc AnsiStyle -> m ()
|
||||||
|
nicelog doc = liftIO $ hPutDoc stdout (doc <> line)
|
||||||
|
|
||||||
|
migrateNCQ1 :: MonadUnliftIO m
|
||||||
|
=> ( Doc AnsiStyle -> IO () )
|
||||||
|
-> AnyStorage
|
||||||
|
-> [SomeRef]
|
||||||
|
-> FilePath
|
||||||
|
-> FilePath
|
||||||
|
-> m ()
|
||||||
|
migrateNCQ1 logger origSto refs a b = flip runContT pure do
|
||||||
|
debug "migrate NCQ to NCQ3"
|
||||||
|
|
||||||
|
ncq <- ContT $ ncqWithStorage b
|
||||||
|
|
||||||
|
let sto = AnyStorage ncq
|
||||||
|
|
||||||
|
let mlog = ncqGetFileName ncq "migrate-ncq1.log"
|
||||||
|
|
||||||
|
debug $ "set SOURCE dir" <+> pretty a
|
||||||
|
|
||||||
|
files <- do
|
||||||
|
fs <- dirFiles a <&> L.filter (\x -> takeExtension x == ".data")
|
||||||
|
mtimes <- liftIO $ mapM getModificationTime fs
|
||||||
|
pure [ f | (f,_) <- L.sortOn (Down . snd) (zip fs mtimes) ]
|
||||||
|
|
||||||
|
touch mlog
|
||||||
|
|
||||||
|
processed <- HS.fromList . lines <$> liftIO (readFile mlog)
|
||||||
|
|
||||||
|
for_ files $ \f -> void $ runMaybeT do
|
||||||
|
|
||||||
|
guard ( not $ HS.member f processed )
|
||||||
|
|
||||||
|
debug $ "processing" <+> pretty f
|
||||||
|
|
||||||
|
ncqStorageScanDataFile0 f $ \offset w key s -> void $ runMaybeT do
|
||||||
|
(t, bs) <- toMPlus (ncqEntryUnwrapValue s)
|
||||||
|
|
||||||
|
case t of
|
||||||
|
B -> do
|
||||||
|
h1 <- putBlock sto (LBS.fromStrict bs)
|
||||||
|
let okay = if Just key == (HashRef <$> h1) then green "ok" else red "fail"
|
||||||
|
liftIO $ logger $ okay <+> pretty t <+> pretty key <+> pretty offset <+> pretty (BS.length bs)
|
||||||
|
|
||||||
|
R -> do
|
||||||
|
debug $ "ommiting reference yet" <+> pretty key
|
||||||
|
|
||||||
|
_ -> none
|
||||||
|
|
||||||
|
|
||||||
|
liftIO $ appendFile mlog (f <> "\n")
|
||||||
|
|
||||||
|
for_ refs $ \(SomeRef r) -> void $ runMaybeT do
|
||||||
|
v <- getRef origSto r >>= toMPlus
|
||||||
|
v0 <- hasBlock origSto v
|
||||||
|
v1 <- hasBlock sto v
|
||||||
|
updateRef sto r v
|
||||||
|
v3 <- getRef sto r
|
||||||
|
let okay = if v3 == Just v then green "ok" else red "fail"
|
||||||
|
liftIO $ logger $ okay <+> "update ref" <+> pretty r <+> pretty v <+> pretty v1 <+> parens (pretty v0)
|
||||||
|
|
||||||
|
|
|
@ -215,6 +215,13 @@ ncqStorageScanDataFile :: MonadIO m
|
||||||
-> m ()
|
-> m ()
|
||||||
ncqStorageScanDataFile ncq fp' action = do
|
ncqStorageScanDataFile ncq fp' action = do
|
||||||
let fp = ncqGetFileName ncq fp'
|
let fp = ncqGetFileName ncq fp'
|
||||||
|
ncqStorageScanDataFile0 fp action
|
||||||
|
|
||||||
|
ncqStorageScanDataFile0 :: MonadIO m
|
||||||
|
=> FilePath
|
||||||
|
-> ( Integer -> Integer -> HashRef -> ByteString -> m () )
|
||||||
|
-> m ()
|
||||||
|
ncqStorageScanDataFile0 fp action = do
|
||||||
mmaped <- liftIO $ logErr "ncqStorageScanDataFile" (mmapFileByteString fp Nothing)
|
mmaped <- liftIO $ logErr "ncqStorageScanDataFile" (mmapFileByteString fp Nothing)
|
||||||
|
|
||||||
flip runContT pure $ callCC \exit -> do
|
flip runContT pure $ callCC \exit -> do
|
||||||
|
|
|
@ -864,6 +864,7 @@ ncq3Tests = do
|
||||||
ncq3EnduranceTest
|
ncq3EnduranceTest
|
||||||
ncq3EnduranceTestInProc
|
ncq3EnduranceTestInProc
|
||||||
|
|
||||||
|
|
||||||
testNCQ3Concurrent1 :: MonadUnliftIO m
|
testNCQ3Concurrent1 :: MonadUnliftIO m
|
||||||
=> Bool
|
=> Bool
|
||||||
-> Int
|
-> Int
|
||||||
|
|
Loading…
Reference in New Issue