1
1
{-# LANGUAGE OverloadedLabels #-}
2
2
{-# LANGUAGE OverloadedStrings #-}
3
- {-# LANGUAGE TemplateHaskell #-}
4
- {-# OPTIONS_GHC -Wno-deferred-out-of-scope-variables #-}
5
3
6
4
-- | Implements a Hydra network component using [etcd](https://etcd.io/).
7
5
--
@@ -61,7 +59,6 @@ import Data.Aeson (decodeFileStrict', encodeFile)
61
59
import Data.Aeson qualified as Aeson
62
60
import Data.Aeson.Lens qualified as Aeson
63
61
import Data.Aeson.Types (Value )
64
- import Data.Bits ((.|.) )
65
62
import Data.ByteString qualified as BS
66
63
import Data.ByteString.Char8 qualified as BS8
67
64
import Data.List ((\\) )
@@ -77,9 +74,8 @@ import Hydra.Network (
77
74
NetworkComponent ,
78
75
NetworkConfiguration (.. ),
79
76
ProtocolVersion ,
80
- WhichEtcd (.. ),
81
77
)
82
- import Hydra.Node.EmbedTH ( embedExecutable )
78
+ import Hydra.Network.EtcdBinary ( getEtcdBinary )
83
79
import Network.GRPC.Client (
84
80
Address (.. ),
85
81
CallParams (.. ),
@@ -108,9 +104,8 @@ import Network.GRPC.Etcd (
108
104
)
109
105
import System.Directory (createDirectoryIfMissing , listDirectory , removeFile )
110
106
import System.Environment.Blank (getEnvironment )
111
- import System.FilePath (takeDirectory , (</>) )
107
+ import System.FilePath ((</>) )
112
108
import System.IO.Error (isDoesNotExistError )
113
- import System.Posix (ownerExecuteMode , ownerReadMode , ownerWriteMode , setFileMode )
114
109
import System.Process (interruptProcessGroupOf )
115
110
import System.Process.Typed (
116
111
Process ,
@@ -254,21 +249,6 @@ withEtcdNetwork tracer protocolVersion config callback action = do
254
249
255
250
NetworkConfiguration {persistenceDir, listen, advertise, peers, whichEtcd} = config
256
251
257
- -- | Return the path of the etcd binary. Will either install it first, or just
258
- -- assume there is one available on the system path.
259
- getEtcdBinary :: FilePath -> WhichEtcd -> IO FilePath
260
- getEtcdBinary _ SystemEtcd = pure " etcd"
261
- getEtcdBinary persistenceDir EmbeddedEtcd =
262
- let path = persistenceDir </> " bin" </> " etcd"
263
- in installEtcd path >> pure path
264
-
265
- -- | Install the embedded 'etcd' binary to given file path.
266
- installEtcd :: FilePath -> IO ()
267
- installEtcd fp = do
268
- createDirectoryIfMissing True (takeDirectory fp)
269
- BS. writeFile fp $ (embedExecutable " etcd" )
270
- setFileMode fp (ownerReadMode .|. ownerWriteMode .|. ownerExecuteMode)
271
-
272
252
-- | Check and write version on etcd cluster. This will retry until we are on a
273
253
-- majority cluster and succeed. If the version does not match a corresponding
274
254
-- 'Connectivity' message is sent via 'NetworkCallback'.
@@ -563,29 +543,31 @@ newPersistentQueue ::
563
543
Natural ->
564
544
m (PersistentQueue m a )
565
545
newPersistentQueue path capacity = do
566
- queue <- newTBQueueIO capacity
546
+ paths <- liftIO $ do
547
+ createDirectoryIfMissing True path
548
+ sort . mapMaybe readMaybe <$> listDirectory path
549
+ queue <- newTBQueueIO $ max (fromIntegral $ length paths) capacity
567
550
highestId <-
568
- try (loadExisting queue) >>= \ case
551
+ try (loadExisting queue paths ) >>= \ case
569
552
Left (_ :: IOException ) -> do
553
+ -- XXX: This swallows and not logs the error
570
554
liftIO $ createDirectoryIfMissing True path
571
555
pure 0
572
556
Right highest -> pure highest
573
557
nextIx <- newTVarIO $ highestId + 1
574
558
pure PersistentQueue {queue, nextIx, directory = path}
575
559
where
576
- loadExisting queue = do
577
- paths <- liftIO $ listDirectory path
578
- case sort $ mapMaybe readMaybe paths of
579
- [] -> pure 0
580
- idxs -> do
581
- forM_ idxs $ \ (idx :: Natural ) -> do
582
- bs <- readFileBS (path </> show idx)
583
- case decodeFull' bs of
584
- Left err ->
585
- fail $ " Failed to decode item: " <> show err
586
- Right item ->
587
- atomically $ writeTBQueue queue (idx, item)
588
- pure $ List. last idxs
560
+ loadExisting queue = \ case
561
+ [] -> pure 0
562
+ idxs -> do
563
+ forM_ idxs $ \ (idx :: Natural ) -> do
564
+ bs <- readFileBS (path </> show idx)
565
+ case decodeFull' bs of
566
+ Left err ->
567
+ fail $ " Failed to decode item: " <> show err
568
+ Right item ->
569
+ atomically $ writeTBQueue queue (idx, item)
570
+ pure $ List. last idxs
589
571
590
572
-- | Write a value to the queue, blocking if the queue is full.
591
573
writePersistentQueue :: (ToCBOR a , MonadSTM m , MonadIO m ) => PersistentQueue m a -> a -> m ()
@@ -595,6 +577,7 @@ writePersistentQueue PersistentQueue{queue, nextIx, directory} item = do
595
577
modifyTVar' nextIx (+ 1 )
596
578
pure next
597
579
writeFileBS (directory </> show next) $ serialize' item
580
+ -- XXX: We should trace when the queue is full
598
581
atomically $ writeTBQueue queue (next, item)
599
582
600
583
-- | Get the next value from the queue without removing it, blocking if the
@@ -610,6 +593,8 @@ popPersistentQueue PersistentQueue{queue, directory} item = do
610
593
popped <- atomically $ do
611
594
(ix, next) <- peekTBQueue queue
612
595
if next == item
596
+ -- FIXME: why would we not call this? We saw the persistent queue reach
597
+ -- capacity and writing blocked while nothing seemed to clear it.
613
598
then readTBQueue queue $> Just ix
614
599
else pure Nothing
615
600
case popped of
0 commit comments