Skip to content

Commit c1f7666

Browse files
authored
Merge pull request #277 from squalus/addtostorenar2
remote: add AddToStoreNar operation
2 parents 21040fb + 5494cc3 commit c1f7666

File tree

13 files changed

+273
-27
lines changed

13 files changed

+273
-27
lines changed

hnix-store-remote/hnix-store-remote.cabal

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ library
8585
, System.Nix.Store.Remote.Types.GC
8686
, System.Nix.Store.Remote.Types.Handshake
8787
, System.Nix.Store.Remote.Types.Logger
88+
, System.Nix.Store.Remote.Types.NoReply
8889
, System.Nix.Store.Remote.Types.ProtoVersion
8990
, System.Nix.Store.Remote.Types.Query
9091
, System.Nix.Store.Remote.Types.Query.Missing
@@ -93,6 +94,7 @@ library
9394
, System.Nix.Store.Remote.Types.StoreReply
9495
, System.Nix.Store.Remote.Types.StoreText
9596
, System.Nix.Store.Remote.Types.SubstituteMode
97+
, System.Nix.Store.Remote.Types.SuccessCodeReply
9698
, System.Nix.Store.Remote.Types.TrustedFlag
9799
, System.Nix.Store.Remote.Types.Verbosity
98100
, System.Nix.Store.Remote.Types.WorkerMagic
@@ -195,6 +197,7 @@ test-suite remote-io
195197
ghc-options: -rtsopts -fprof-auto "-with-rtsopts -V0"
196198
other-modules:
197199
NixDaemonSpec
200+
, SampleNar
198201
build-depends:
199202
base >=4.12 && <5
200203
, hnix-store-core
@@ -205,6 +208,8 @@ test-suite remote-io
205208
, concurrency
206209
, containers
207210
, crypton
211+
, data-default-class
212+
, dependent-sum
208213
, directory
209214
, exceptions
210215
, filepath
@@ -215,5 +220,6 @@ test-suite remote-io
215220
, some
216221
, temporary
217222
, text
223+
, time
218224
, unix
219225
, unordered-containers

hnix-store-remote/src/System/Nix/Store/Remote/Client.hs

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
module System.Nix.Store.Remote.Client
22
( addToStore
3+
, addToStoreNar
34
, addTextToStore
45
, addSignatures
56
, addTempRoot
@@ -26,12 +27,14 @@ module System.Nix.Store.Remote.Client
2627
, module System.Nix.Store.Remote.Client.Core
2728
) where
2829

29-
import Control.Monad (when)
30+
import Control.Monad (void, when)
3031
import Control.Monad.Except (throwError)
32+
import Data.ByteString (ByteString)
3133
import Data.HashSet (HashSet)
3234
import Data.Map (Map)
3335
import Data.Set (Set)
3436
import Data.Some (Some)
37+
import Data.Word (Word64)
3538

3639
import System.Nix.Build (BuildMode, BuildResult)
3740
import System.Nix.DerivedPath (DerivedPath)
@@ -73,6 +76,19 @@ addToStore name source method hashAlgo repair = do
7376
setNarSource source
7477
doReq (AddToStore name method hashAlgo repair)
7578

79+
addToStoreNar
80+
:: MonadRemoteStore m
81+
=> StorePath
82+
-> Metadata StorePath
83+
-> RepairMode
84+
-> CheckMode
85+
-> (Word64 -> IO(Maybe ByteString))
86+
-> m ()
87+
addToStoreNar path metadata repair checkSigs source = do
88+
setDataSource source
89+
void $ doReq (AddToStoreNar path metadata repair checkSigs)
90+
pure ()
91+
7692
-- | Add @StoreText@ to the store
7793
-- Reference accepts repair but only uses it
7894
-- to throw error in case of remote talking to nix-daemon.
@@ -96,7 +112,7 @@ addSignatures
96112
=> StorePath
97113
-> Set Signature
98114
-> m ()
99-
addSignatures p signatures = doReq (AddSignatures p signatures)
115+
addSignatures p signatures = (void . doReq) (AddSignatures p signatures)
100116

101117
-- | Add temporary garbage collector root.
102118
--
@@ -105,14 +121,14 @@ addTempRoot
105121
:: MonadRemoteStore m
106122
=> StorePath
107123
-> m ()
108-
addTempRoot = doReq . AddTempRoot
124+
addTempRoot = void . doReq . AddTempRoot
109125

110126
-- | Add indirect garbage collector root.
111127
addIndirectRoot
112128
:: MonadRemoteStore m
113129
=> StorePath
114130
-> m ()
115-
addIndirectRoot = doReq . AddIndirectRoot
131+
addIndirectRoot = void . doReq . AddIndirectRoot
116132

117133
-- | Build a derivation available at @StorePath@
118134
buildDerivation
@@ -139,7 +155,7 @@ buildPaths
139155
=> Set DerivedPath
140156
-> BuildMode
141157
-> m ()
142-
buildPaths a b = doReq (BuildPaths a b)
158+
buildPaths a b = (void . doReq) (BuildPaths a b)
143159

144160
collectGarbage
145161
:: MonadRemoteStore m
@@ -151,7 +167,7 @@ ensurePath
151167
:: MonadRemoteStore m
152168
=> StorePath
153169
-> m ()
154-
ensurePath = doReq . EnsurePath
170+
ensurePath = void . doReq . EnsurePath
155171

156172
-- | Find garbage collector roots.
157173
findRoots
@@ -235,12 +251,12 @@ queryMissing = doReq . QueryMissing
235251
optimiseStore
236252
:: MonadRemoteStore m
237253
=> m ()
238-
optimiseStore = doReq OptimiseStore
254+
optimiseStore = (void . doReq) OptimiseStore
239255

240256
syncWithGC
241257
:: MonadRemoteStore m
242258
=> m ()
243-
syncWithGC = doReq SyncWithGC
259+
syncWithGC = (void . doReq) SyncWithGC
244260

245261
verifyStore
246262
:: MonadRemoteStore m

hnix-store-remote/src/System/Nix/Store/Remote/Client/Core.hs

Lines changed: 58 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,13 @@ module System.Nix.Store.Remote.Client.Core
77
import Control.Monad (unless, when)
88
import Control.Monad.Except (throwError)
99
import Control.Monad.IO.Class (MonadIO, liftIO)
10+
import Data.ByteString (ByteString)
1011
import Data.DList (DList)
1112
import Data.Some (Some(Some))
13+
import Data.Word (Word64)
14+
import Network.Socket (Socket)
1215
import System.Nix.Nar (NarSource)
16+
import System.Nix.StorePath.Metadata (Metadata(..))
1317
import System.Nix.Store.Remote.Logger (processOutput)
1418
import System.Nix.Store.Remote.MonadStore
1519
( MonadRemoteStore(..)
@@ -28,11 +32,13 @@ import System.Nix.Store.Remote.Serializer
2832
)
2933
import System.Nix.Store.Remote.Types.Handshake (ClientHandshakeOutput(..))
3034
import System.Nix.Store.Remote.Types.Logger (Logger)
35+
import System.Nix.Store.Remote.Types.NoReply (NoReply(..))
3136
import System.Nix.Store.Remote.Types.ProtoVersion (ProtoVersion(..))
3237
import System.Nix.Store.Remote.Types.StoreRequest (StoreRequest(..))
3338
import System.Nix.Store.Remote.Types.StoreReply (StoreReply(..))
3439
import System.Nix.Store.Remote.Types.WorkerMagic (WorkerMagic(..))
3540

41+
import qualified Data.ByteString
3642
import qualified Network.Socket.ByteString
3743

3844
type Run m a = m (Either RemoteStoreError a, DList Logger)
@@ -69,14 +75,58 @@ doReq = \case
6975
Nothing ->
7076
throwError
7177
RemoteStoreError_NoNarSourceProvided
72-
73-
_ -> pure ()
74-
75-
processOutput
76-
sockGetS
77-
(mapErrorS RemoteStoreError_SerializerReply
78-
$ getReplyS @a
79-
)
78+
processOutput
79+
processReply
80+
81+
AddToStoreNar _ meta _ _ -> do
82+
let narBytes = maybe 0 id $ metadataNarBytes meta
83+
maybeDataSource <- takeDataSource
84+
soc <- getStoreSocket
85+
case maybeDataSource of
86+
Nothing ->
87+
if narBytes == 0 then writeFramedSource (const (pure Nothing)) soc 0
88+
else throwError RemoteStoreError_NoDataSourceProvided
89+
Just dataSource -> do
90+
writeFramedSource dataSource soc narBytes
91+
processOutput
92+
pure NoReply
93+
94+
_ -> do
95+
processOutput
96+
processReply
97+
98+
where
99+
processReply = sockGetS
100+
(mapErrorS RemoteStoreError_SerializerReply
101+
$ getReplyS @a
102+
)
103+
104+
writeFramedSource
105+
:: forall m
106+
. ( MonadIO m
107+
, MonadRemoteStore m
108+
)
109+
=> (Word64 -> IO(Maybe ByteString))
110+
-> Socket
111+
-> Word64
112+
-> m ()
113+
writeFramedSource dataSource soc remainingBytes = do
114+
let chunkSize = 16384
115+
maybeBytes <- liftIO $ dataSource chunkSize
116+
case maybeBytes of
117+
Nothing -> do
118+
unless (remainingBytes == 0) $ throwError RemoteStoreError_DataSourceExhausted
119+
let eof :: Word64 = 0
120+
sockPutS int eof
121+
Just bytes -> do
122+
let bytesInChunk = fromIntegral $ Data.ByteString.length bytes
123+
when (bytesInChunk > chunkSize || bytesInChunk > remainingBytes) $ throwError RemoteStoreError_DataSourceReadTooLarge
124+
when (bytesInChunk == 0) $ throwError RemoteStoreError_DataSourceZeroLengthRead
125+
sockPutS int bytesInChunk
126+
liftIO
127+
$ Network.Socket.ByteString.sendAll soc bytes
128+
let nextRemainingBytes = remainingBytes - bytesInChunk
129+
writeFramedSource dataSource soc nextRemainingBytes
80130

81131
greetServer
82132
:: MonadRemoteStore m

hnix-store-remote/src/System/Nix/Store/Remote/MonadStore.hs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ data RemoteStoreError
7777
| RemoteStoreError_LoggerParserFail String ByteString -- when incremental parser returns ((Fail msg leftover) :: Result)
7878
| RemoteStoreError_NoDataSourceProvided -- remoteStoreStateMDataSource is required but it is Nothing
7979
| RemoteStoreError_DataSourceExhausted -- remoteStoreStateMDataSource returned Nothing but more data was requested
80+
| RemoteStoreError_DataSourceZeroLengthRead -- remoteStoreStateMDataSource returned a zero length ByteString
81+
| RemoteStoreError_DataSourceReadTooLarge -- remoteStoreStateMDataSource returned a ByteString larger than the chunk size requested or the remaining bytes
8082
| RemoteStoreError_NoDataSinkProvided -- remoteStoreStateMDataSink is required but it is Nothing
8183
| RemoteStoreError_NoNarSourceProvided
8284
| RemoteStoreError_OperationFailed
@@ -250,6 +252,15 @@ class ( MonadIO m
250252
-> m ()
251253
setDataSource x = lift (setDataSource x)
252254

255+
takeDataSource :: m (Maybe (Word64 -> IO (Maybe ByteString)))
256+
default takeDataSource
257+
:: ( MonadTrans t
258+
, MonadRemoteStore m'
259+
, m ~ t m'
260+
)
261+
=> m (Maybe (Word64 -> IO (Maybe ByteString)))
262+
takeDataSource = lift takeDataSource
263+
253264
getDataSource :: m (Maybe (Word64 -> IO (Maybe ByteString)))
254265
default getDataSource
255266
:: ( MonadTrans t
@@ -327,6 +338,11 @@ instance MonadIO m => MonadRemoteStore (RemoteStoreT m) where
327338
getDataSource = RemoteStoreT (gets remoteStoreStateMDataSource)
328339
clearDataSource = RemoteStoreT $ modify $ \s -> s { remoteStoreStateMDataSource = Nothing }
329340

341+
takeDataSource = RemoteStoreT $ do
342+
x <- remoteStoreStateMDataSource <$> get
343+
modify $ \s -> s { remoteStoreStateMDataSource = Nothing }
344+
pure x
345+
330346
setDataSink x = RemoteStoreT $ modify $ \s -> s { remoteStoreStateMDataSink = pure x }
331347
getDataSink = RemoteStoreT (gets remoteStoreStateMDataSink)
332348
clearDataSink = RemoteStoreT $ modify $ \s -> s { remoteStoreStateMDataSink = Nothing }

hnix-store-remote/src/System/Nix/Store/Remote/Serializer.hs

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ module System.Nix.Store.Remote.Serializer
8585
-- ** Reply
8686
, ReplySError(..)
8787
, opSuccess
88+
, noop
8889
-- *** Realisation
8990
, derivationOutputTyped
9091
, realisation
@@ -1077,6 +1078,16 @@ storeRequest = Serializer
10771078

10781079
pure $ Some (AddToStore pathName recursive hashAlgo repair)
10791080

1081+
WorkerOp_AddToStoreNar -> mapGetE $ do
1082+
storePath' <- getS storePath
1083+
metadata <- getS pathMetadata
1084+
repair <- getS bool
1085+
let repairMode = if repair then RepairMode_DoRepair else RepairMode_DontRepair
1086+
dontCheckSigs <- getS bool
1087+
let checkSigs = if dontCheckSigs then CheckMode_DontCheck else CheckMode_DoCheck
1088+
1089+
pure $ Some (AddToStoreNar storePath' metadata repairMode checkSigs)
1090+
10801091
WorkerOp_AddTextToStore -> mapGetE $ do
10811092
txt <- getS storeText
10821093
paths <- getS (hashSet storePath)
@@ -1175,7 +1186,6 @@ storeRequest = Serializer
11751186

11761187
w@WorkerOp_AddBuildLog -> notYet w
11771188
w@WorkerOp_AddMultipleToStore -> notYet w
1178-
w@WorkerOp_AddToStoreNar -> notYet w
11791189
w@WorkerOp_BuildPathsWithResults -> notYet w
11801190
w@WorkerOp_ClearFailedPaths -> notYet w
11811191
w@WorkerOp_ExportPath -> notYet w
@@ -1207,6 +1217,14 @@ storeRequest = Serializer
12071217
putS bool (recursive == FileIngestionMethod_FileRecursive)
12081218
putS someHashAlgo hashAlgo
12091219

1220+
Some (AddToStoreNar storePath' metadata repair checkSigs) -> mapPutE $ do
1221+
putS workerOp WorkerOp_AddToStoreNar
1222+
1223+
putS storePath storePath'
1224+
putS pathMetadata metadata
1225+
putS bool $ repair == RepairMode_DoRepair
1226+
putS bool $ checkSigs == CheckMode_DontCheck
1227+
12101228
Some (AddTextToStore txt paths _repair) -> mapPutE $ do
12111229
putS workerOp WorkerOp_AddTextToStore
12121230

@@ -1368,17 +1386,23 @@ mapPutER = mapErrorST ReplySError_PrimPut
13681386
-- | Parse a bool returned at the end of simple operations.
13691387
-- This is always 1 (@True@) so we assert that it really is so.
13701388
-- Errors for these operations are indicated via @Logger_Error@.
1371-
opSuccess :: NixSerializer r ReplySError ()
1389+
opSuccess :: NixSerializer r ReplySError SuccessCodeReply
13721390
opSuccess = Serializer
13731391
{ getS = do
13741392
retCode <- mapGetER $ getS bool
13751393
Control.Monad.unless
13761394
(retCode == True)
13771395
$ throwError ReplySError_UnexpectedFalseOpSuccess
1378-
pure ()
1396+
pure SuccessCodeReply
13791397
, putS = \_ -> mapPutER $ putS bool True
13801398
}
13811399

1400+
noop :: a -> NixSerializer r ReplySError a
1401+
noop ret = Serializer
1402+
{ getS = pure ret
1403+
, putS = \_ -> pure ()
1404+
}
1405+
13821406
-- *** Realisation
13831407

13841408
derivationOutputTyped :: NixSerializer r ReplySError (System.Nix.Realisation.DerivationOutput OutputName)

hnix-store-remote/src/System/Nix/Store/Remote/Server.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ processConnection workerHelper postGreet sock = do
170170
-- out of thin air
171171
() <- Data.Some.withSome someReq $ \case
172172
r@AddToStore {} -> perform r
173+
r@AddToStoreNar {} -> perform r
173174
r@AddTextToStore {} -> perform r
174175
r@AddSignatures {} -> perform r
175176
r@AddTempRoot {} -> perform r

hnix-store-remote/src/System/Nix/Store/Remote/Types.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ module System.Nix.Store.Remote.Types
99
, module System.Nix.Store.Remote.Types.StoreRequest
1010
, module System.Nix.Store.Remote.Types.StoreText
1111
, module System.Nix.Store.Remote.Types.SubstituteMode
12+
, module System.Nix.Store.Remote.Types.SuccessCodeReply
1213
, module System.Nix.Store.Remote.Types.TrustedFlag
1314
, module System.Nix.Store.Remote.Types.Verbosity
1415
, module System.Nix.Store.Remote.Types.WorkerMagic
@@ -25,6 +26,7 @@ import System.Nix.Store.Remote.Types.StoreConfig
2526
import System.Nix.Store.Remote.Types.StoreRequest
2627
import System.Nix.Store.Remote.Types.StoreText
2728
import System.Nix.Store.Remote.Types.SubstituteMode
29+
import System.Nix.Store.Remote.Types.SuccessCodeReply
2830
import System.Nix.Store.Remote.Types.TrustedFlag
2931
import System.Nix.Store.Remote.Types.Verbosity
3032
import System.Nix.Store.Remote.Types.WorkerMagic
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
module System.Nix.Store.Remote.Types.NoReply
2+
( NoReply(..)
3+
) where
4+
5+
-- | Reply type for the case where the server does not reply
6+
data NoReply = NoReply
7+
deriving (Show)
8+

0 commit comments

Comments
 (0)