mirror of https://github.com/voidlizard/hbs2
wip
This commit is contained in:
parent
569b55d401
commit
7597ed2822
|
@ -92,7 +92,7 @@ data NCQStorage =
|
||||||
, ncqMaxCachedIdx :: Int
|
, ncqMaxCachedIdx :: Int
|
||||||
, ncqMaxCachedData :: Int
|
, ncqMaxCachedData :: Int
|
||||||
, ncqRefsMem :: TVar (HashMap HashRef HashRef)
|
, ncqRefsMem :: TVar (HashMap HashRef HashRef)
|
||||||
, ncqRefsDirty :: TVar Bool
|
, ncqRefsDirty :: TVar Int
|
||||||
, ncqWriteQueue :: TVar (HashPSQ HashRef TimeSpec LBS.ByteString)
|
, ncqWriteQueue :: TVar (HashPSQ HashRef TimeSpec LBS.ByteString)
|
||||||
, ncqWaitIndex :: TVar (HashPSQ HashRef TimeSpec (Word64,Word64))
|
, ncqWaitIndex :: TVar (HashPSQ HashRef TimeSpec (Word64,Word64))
|
||||||
, ncqTrackedFiles :: TVar (HashSet FileKey)
|
, ncqTrackedFiles :: TVar (HashSet FileKey)
|
||||||
|
@ -104,7 +104,7 @@ data NCQStorage =
|
||||||
, ncqCurrentHandleR :: TVar Fd
|
, ncqCurrentHandleR :: TVar Fd
|
||||||
, ncqCurrentUsage :: TVar (IntMap Int)
|
, ncqCurrentUsage :: TVar (IntMap Int)
|
||||||
, ncqCurrentReadReq :: TVar (Seq (Fd, Word64, Word64, TMVar ByteString))
|
, ncqCurrentReadReq :: TVar (Seq (Fd, Word64, Word64, TMVar ByteString))
|
||||||
, ncqFlushNow :: TQueue ()
|
, ncqFlushNow :: TVar Int
|
||||||
, ncqOpenDone :: TMVar Bool
|
, ncqOpenDone :: TMVar Bool
|
||||||
, ncqStopped :: TVar Bool
|
, ncqStopped :: TVar Bool
|
||||||
}
|
}
|
||||||
|
@ -154,6 +154,9 @@ ncqGetNewFossilName n@NCQStorage{} = do
|
||||||
let (p,tpl) = splitFileName fn
|
let (p,tpl) = splitFileName fn
|
||||||
liftIO $ emptyTempFile p tpl
|
liftIO $ emptyTempFile p tpl
|
||||||
|
|
||||||
|
ncqGetRefsDataFileName :: NCQStorage -> FilePath
|
||||||
|
ncqGetRefsDataFileName ncq = ncqGetFileName ncq "refs.data"
|
||||||
|
|
||||||
ncqGetIndexFileName :: NCQStorage -> FileKey -> FilePath
|
ncqGetIndexFileName :: NCQStorage -> FileKey -> FilePath
|
||||||
ncqGetIndexFileName ncq fk = do
|
ncqGetIndexFileName ncq fk = do
|
||||||
ncqGetFileName ncq (addExtension (dropExtension (BS8.unpack (coerce fk))) ".cq")
|
ncqGetFileName ncq (addExtension (dropExtension (BS8.unpack (coerce fk))) ".cq")
|
||||||
|
@ -242,8 +245,8 @@ ncqIndexFile n@NCQStorage{} fp' = do
|
||||||
|
|
||||||
ncqStorageStop :: MonadUnliftIO m => NCQStorage -> m ()
|
ncqStorageStop :: MonadUnliftIO m => NCQStorage -> m ()
|
||||||
ncqStorageStop ncq@NCQStorage{..} = do
|
ncqStorageStop ncq@NCQStorage{..} = do
|
||||||
atomically $ writeTVar ncqStopped True
|
|
||||||
ncqStorageSync ncq
|
ncqStorageSync ncq
|
||||||
|
atomically $ writeTVar ncqStopped True
|
||||||
atomically $ fix \next -> do
|
atomically $ fix \next -> do
|
||||||
done <- readTVar ncqWriteQueue <&> HPSQ.null
|
done <- readTVar ncqWriteQueue <&> HPSQ.null
|
||||||
unless done STM.retry
|
unless done STM.retry
|
||||||
|
@ -255,6 +258,11 @@ ncqStorageRun ncq@NCQStorage{..} = flip runContT pure do
|
||||||
let dumpData = 1024 ^ 2
|
let dumpData = 1024 ^ 2
|
||||||
let syncData = fromIntegral ncqSyncSize
|
let syncData = fromIntegral ncqSyncSize
|
||||||
|
|
||||||
|
let untilStopped m = fix \loop -> do
|
||||||
|
m >> readTVarIO ncqStopped >>= \case
|
||||||
|
False -> loop
|
||||||
|
_ -> debug "STOPPING THREAD"
|
||||||
|
|
||||||
ContT $ bracket none $ const $ liftIO do
|
ContT $ bracket none $ const $ liftIO do
|
||||||
-- writeJournal syncData
|
-- writeJournal syncData
|
||||||
readTVarIO ncqCurrentHandleW >>= closeFd
|
readTVarIO ncqCurrentHandleW >>= closeFd
|
||||||
|
@ -264,7 +272,30 @@ ncqStorageRun ncq@NCQStorage{..} = flip runContT pure do
|
||||||
-- cap <- (10*) <$> getNumCapabilities
|
-- cap <- (10*) <$> getNumCapabilities
|
||||||
cap <- getNumCapabilities
|
cap <- getNumCapabilities
|
||||||
|
|
||||||
reader <- ContT $ withAsync $ forever do
|
refsWriter <- ContT $ withAsync $ untilStopped do
|
||||||
|
-- FIXME: timeout-hardcode
|
||||||
|
|
||||||
|
void $ race (pause @'Seconds 2) $ atomically do
|
||||||
|
readTVar ncqStopped `orElse` STM.retry
|
||||||
|
|
||||||
|
dirty <- readTVarIO ncqRefsDirty
|
||||||
|
|
||||||
|
when (dirty > 0) do
|
||||||
|
refs <- readTVarIO ncqRefsMem <&> HM.toList
|
||||||
|
withBinaryFileDurableAtomic (ncqGetRefsDataFileName ncq) WriteMode $ \fh -> do
|
||||||
|
for_ refs $ \(k,v) -> do
|
||||||
|
let ks = coerce @_ @ByteString k
|
||||||
|
let vs = coerce @_ @ByteString v
|
||||||
|
let w = 4 + BS.length ks + BS.length vs -- always 4+64, but okay
|
||||||
|
liftIO do
|
||||||
|
BS.hPutStr fh (N.bytestring32 (fromIntegral w))
|
||||||
|
BS.hPutStr fh ks
|
||||||
|
BS.hPutStr fh vs
|
||||||
|
atomically $ writeTVar ncqRefsDirty 0
|
||||||
|
|
||||||
|
link refsWriter
|
||||||
|
|
||||||
|
reader <- ContT $ withAsync $ untilStopped do
|
||||||
|
|
||||||
reqs <- atomically do
|
reqs <- atomically do
|
||||||
xs <- stateTVar ncqCurrentReadReq (Seq.splitAt cap)
|
xs <- stateTVar ncqCurrentReadReq (Seq.splitAt cap)
|
||||||
|
@ -281,8 +312,19 @@ ncqStorageRun ncq@NCQStorage{..} = flip runContT pure do
|
||||||
|
|
||||||
indexQ <- newTQueueIO
|
indexQ <- newTQueueIO
|
||||||
|
|
||||||
indexer <- ContT $ withAsync $ forever do
|
indexer <- ContT $ withAsync $ untilStopped do
|
||||||
(fd, fn) <- atomically (readTQueue indexQ)
|
|
||||||
|
what <- atomically do
|
||||||
|
e <- tryReadTQueue indexQ
|
||||||
|
stop <- readTVar ncqStopped
|
||||||
|
|
||||||
|
case e of
|
||||||
|
Just x -> pure (Just x)
|
||||||
|
Nothing | stop -> pure Nothing
|
||||||
|
| otherwise -> STM.retry
|
||||||
|
|
||||||
|
for_ what $ \(fd,fn) -> do
|
||||||
|
|
||||||
key <- ncqIndexFile ncq fn <&> fromString @FileKey
|
key <- ncqIndexFile ncq fn <&> fromString @FileKey
|
||||||
|
|
||||||
atomically do
|
atomically do
|
||||||
|
@ -293,11 +335,16 @@ ncqStorageRun ncq@NCQStorage{..} = flip runContT pure do
|
||||||
|
|
||||||
link indexer
|
link indexer
|
||||||
|
|
||||||
fix \loop -> do
|
writer <- ContT $ withAsync $ untilStopped do
|
||||||
|
|
||||||
flush <- liftIO $ race (pause @'Seconds ( realToFrac dumpTimeout / 4e6 )) $ atomically do
|
flush <- liftIO $ race (pause @'Seconds ( realToFrac dumpTimeout / 4e6 )) $ atomically do
|
||||||
peekTQueue ncqFlushNow >> STM.flushTQueue ncqFlushNow
|
flush <- readTVar ncqFlushNow
|
||||||
|
stop <- readTVar ncqStopped
|
||||||
|
if flush > 0 || stop then do
|
||||||
|
writeTVar ncqFlushNow 0
|
||||||
pure True
|
pure True
|
||||||
|
else do
|
||||||
|
STM.retry
|
||||||
|
|
||||||
let flushNow = fromRight False flush
|
let flushNow = fromRight False flush
|
||||||
|
|
||||||
|
@ -307,16 +354,14 @@ ncqStorageRun ncq@NCQStorage{..} = flip runContT pure do
|
||||||
|
|
||||||
let dumpByTime = toMicroSeconds (TimeoutTS (now - lastW)) > dumpTimeout && bytes > 0
|
let dumpByTime = toMicroSeconds (TimeoutTS (now - lastW)) > dumpTimeout && bytes > 0
|
||||||
|
|
||||||
when (dumpByTime || bytes >= dumpData || flushNow) do
|
stopped <- readTVarIO ncqStopped
|
||||||
-- debug "NCQStorage: dump data!"
|
|
||||||
|
when (dumpByTime || bytes >= dumpData || flushNow || stopped) do
|
||||||
|
debug "NCQStorage: dump data!"
|
||||||
liftIO $ writeJournal indexQ syncData
|
liftIO $ writeJournal indexQ syncData
|
||||||
|
|
||||||
done <- atomically do
|
mapM_ waitCatch [writer,indexer,refsWriter]
|
||||||
mt <- readTVar ncqWriteQueue <&> HPSQ.null
|
mapM_ cancel [reader]
|
||||||
stop <- readTVar ncqStopped
|
|
||||||
pure (mt && stop)
|
|
||||||
|
|
||||||
unless done loop
|
|
||||||
|
|
||||||
where
|
where
|
||||||
|
|
||||||
|
@ -583,14 +628,27 @@ ncqStorageGet ncq@NCQStorage{..} h = do
|
||||||
|
|
||||||
pure $ Just $ LBS.fromStrict $ BS.take (fromIntegral l) (BS.drop (fromIntegral o+4+32) mmaped)
|
pure $ Just $ LBS.fromStrict $ BS.take (fromIntegral l) (BS.drop (fromIntegral o+4+32) mmaped)
|
||||||
|
|
||||||
|
ncqStorageGetRef :: MonadUnliftIO m => NCQStorage -> HashRef -> m (Maybe HashRef)
|
||||||
|
ncqStorageGetRef NCQStorage{..} ref = readTVarIO ncqRefsMem <&> HM.lookup ref
|
||||||
|
|
||||||
|
ncqStorageSetRef :: MonadUnliftIO m => NCQStorage -> HashRef -> HashRef -> m ()
|
||||||
|
ncqStorageSetRef NCQStorage{..} ref val = atomically do
|
||||||
|
stopped <- readTVar ncqStopped
|
||||||
|
unless stopped do
|
||||||
|
modifyTVar ncqRefsMem (HM.insert ref val)
|
||||||
|
modifyTVar ncqRefsDirty succ
|
||||||
|
|
||||||
|
ncqStorageDelRef :: MonadUnliftIO m => NCQStorage -> HashRef -> m ()
|
||||||
|
ncqStorageDelRef NCQStorage{..} ref = atomically do
|
||||||
|
modifyTVar ncqRefsMem (HM.delete ref)
|
||||||
|
|
||||||
ncqStorageDel :: MonadUnliftIO m => NCQStorage -> HashRef -> m NCQStorage
|
ncqStorageDel :: MonadUnliftIO m => NCQStorage -> HashRef -> m NCQStorage
|
||||||
ncqStorageDel sto h = do
|
ncqStorageDel sto h = do
|
||||||
error "not implemented yet"
|
error "not implemented yet"
|
||||||
|
|
||||||
ncqStorageSync :: MonadUnliftIO m => NCQStorage -> m ()
|
ncqStorageSync :: MonadUnliftIO m => NCQStorage -> m ()
|
||||||
ncqStorageSync NCQStorage{..} = do
|
ncqStorageSync NCQStorage{..} = do
|
||||||
atomically $ writeTQueue ncqFlushNow ()
|
atomically $ modifyTVar ncqFlushNow succ
|
||||||
|
|
||||||
|
|
||||||
ncqLoadSomeIndexes :: MonadIO m => NCQStorage -> [FileKey] -> m ()
|
ncqLoadSomeIndexes :: MonadIO m => NCQStorage -> [FileKey] -> m ()
|
||||||
ncqLoadSomeIndexes ncq@NCQStorage{..} keys = do
|
ncqLoadSomeIndexes ncq@NCQStorage{..} keys = do
|
||||||
|
@ -631,10 +689,21 @@ ncqStorageOpen fp = do
|
||||||
ncqFixIndexes ncq
|
ncqFixIndexes ncq
|
||||||
ncqLoadIndexes ncq
|
ncqLoadIndexes ncq
|
||||||
readCurrent ncq
|
readCurrent ncq
|
||||||
|
readRefs ncq
|
||||||
atomically $ putTMVar ncqOpenDone True
|
atomically $ putTMVar ncqOpenDone True
|
||||||
pure ncq
|
pure ncq
|
||||||
|
|
||||||
where
|
where
|
||||||
|
|
||||||
|
readRefs ncq@NCQStorage{..} = do
|
||||||
|
mmaped <- liftIO $ mmapFileByteString (ncqGetRefsDataFileName ncq) Nothing
|
||||||
|
kvs <- S.toList_ do
|
||||||
|
scanBS mmaped $ \bs -> do
|
||||||
|
let k = BS.copy (BS.take 32 bs) & coerce @_ @HashRef
|
||||||
|
let v = BS.copy (BS.take 32 (BS.drop 32 bs)) & coerce @_ @HashRef
|
||||||
|
S.yield (k,v)
|
||||||
|
atomically $ writeTVar ncqRefsMem (HM.fromList kvs)
|
||||||
|
|
||||||
readCurrent ncq@NCQStorage{..} = do
|
readCurrent ncq@NCQStorage{..} = do
|
||||||
let fn = ncqGetCurrentName ncq
|
let fn = ncqGetCurrentName ncq
|
||||||
-- liftIO $ print $ pretty "FILE" <+> pretty fn
|
-- liftIO $ print $ pretty "FILE" <+> pretty fn
|
||||||
|
@ -691,7 +760,7 @@ ncqStorageInit_ check path = do
|
||||||
let ncqRoot = path
|
let ncqRoot = path
|
||||||
|
|
||||||
ncqRefsMem <- newTVarIO mempty
|
ncqRefsMem <- newTVarIO mempty
|
||||||
ncqRefsDirty <- newTVarIO False
|
ncqRefsDirty <- newTVarIO 0
|
||||||
|
|
||||||
let ncqSyncSize = 32 * (1024 ^ 2)
|
let ncqSyncSize = 32 * (1024 ^ 2)
|
||||||
let ncqMinLog = 2 * (1024 ^ 3)
|
let ncqMinLog = 2 * (1024 ^ 3)
|
||||||
|
@ -706,7 +775,7 @@ ncqStorageInit_ check path = do
|
||||||
ncqLastWritten <- getTimeCoarse >>= newTVarIO
|
ncqLastWritten <- getTimeCoarse >>= newTVarIO
|
||||||
ncqWaitIndex <- newTVarIO HPSQ.empty
|
ncqWaitIndex <- newTVarIO HPSQ.empty
|
||||||
|
|
||||||
ncqFlushNow <- newTQueueIO
|
ncqFlushNow <- newTVarIO 0
|
||||||
ncqOpenDone <- newEmptyTMVarIO
|
ncqOpenDone <- newEmptyTMVarIO
|
||||||
ncqCurrentReadReq <- newTVarIO mempty
|
ncqCurrentReadReq <- newTVarIO mempty
|
||||||
ncqCurrentUsage <- newTVarIO mempty
|
ncqCurrentUsage <- newTVarIO mempty
|
||||||
|
@ -725,6 +794,7 @@ ncqStorageInit_ check path = do
|
||||||
let ncqCurrentHandleW = undefined
|
let ncqCurrentHandleW = undefined
|
||||||
let ncqCurrentHandleR = undefined
|
let ncqCurrentHandleR = undefined
|
||||||
let ncq0 = NCQStorage{..}
|
let ncq0 = NCQStorage{..}
|
||||||
|
|
||||||
lastSz <- try @_ @IOException (BS.readFile currentSize)
|
lastSz <- try @_ @IOException (BS.readFile currentSize)
|
||||||
<&> either (const 0) N.word64
|
<&> either (const 0) N.word64
|
||||||
|
|
||||||
|
@ -752,6 +822,10 @@ ncqStorageInit_ check path = do
|
||||||
|
|
||||||
debug $ "currentFileName" <+> pretty (ncqGetCurrentName_ path ncqGen)
|
debug $ "currentFileName" <+> pretty (ncqGetCurrentName_ path ncqGen)
|
||||||
|
|
||||||
pure $ NCQStorage{..}
|
let ncq = NCQStorage{..}
|
||||||
|
|
||||||
|
touch (ncqGetRefsDataFileName ncq)
|
||||||
|
|
||||||
|
pure ncq
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -311,6 +311,7 @@ main = do
|
||||||
h2 <- lift $ ncqStoragePut ncq "PECHENTRESKI!"
|
h2 <- lift $ ncqStoragePut ncq "PECHENTRESKI!"
|
||||||
|
|
||||||
liftIO $ ncqStorageStop ncq
|
liftIO $ ncqStorageStop ncq
|
||||||
|
wait writer
|
||||||
|
|
||||||
pure $ mkList [mkSym (show $ pretty h), mkSym (show $ pretty h2)]
|
pure $ mkList [mkSym (show $ pretty h), mkSym (show $ pretty h2)]
|
||||||
|
|
||||||
|
@ -402,6 +403,7 @@ main = do
|
||||||
href <- liftIO $ ncqStoragePut ncq (LBS.fromStrict what)
|
href <- liftIO $ ncqStoragePut ncq (LBS.fromStrict what)
|
||||||
|
|
||||||
liftIO $ ncqStorageStop ncq
|
liftIO $ ncqStorageStop ncq
|
||||||
|
wait writer
|
||||||
|
|
||||||
pure $ maybe nil (mkSym . show . pretty) href
|
pure $ maybe nil (mkSym . show . pretty) href
|
||||||
|
|
||||||
|
@ -442,7 +444,26 @@ main = do
|
||||||
|
|
||||||
liftIO $ print $ pretty m
|
liftIO $ print $ pretty m
|
||||||
|
|
||||||
|
debug "stopping"
|
||||||
liftIO $ ncqStorageStop ncq
|
liftIO $ ncqStorageStop ncq
|
||||||
|
debug "stopping done"
|
||||||
|
|
||||||
|
wait writer
|
||||||
|
|
||||||
|
e -> throwIO $ BadFormException @C (mkList e)
|
||||||
|
|
||||||
|
entry $ bindMatch "test:ncq:one-ref" $ nil_ $ \case
|
||||||
|
[StringLike fn] -> liftIO $ flip runContT pure do
|
||||||
|
|
||||||
|
ncq <- lift $ ncqStorageOpen fn
|
||||||
|
|
||||||
|
writer <- ContT $ withAsync $ ncqStorageRun ncq
|
||||||
|
link writer
|
||||||
|
|
||||||
|
ContT $ bracket none $ const do
|
||||||
|
none
|
||||||
|
|
||||||
|
none
|
||||||
|
|
||||||
e -> throwIO $ BadFormException @C (mkList e)
|
e -> throwIO $ BadFormException @C (mkList e)
|
||||||
|
|
||||||
|
@ -477,34 +498,10 @@ main = do
|
||||||
|
|
||||||
liftIO $ ncqStorageStop ncq
|
liftIO $ ncqStorageStop ncq
|
||||||
|
|
||||||
|
wait writer
|
||||||
|
|
||||||
e -> throwIO $ BadFormException @C (mkList e)
|
e -> throwIO $ BadFormException @C (mkList e)
|
||||||
|
|
||||||
entry $ bindMatch "test:retry" $ nil_ $ const $ flip runContT pure do
|
|
||||||
|
|
||||||
q <- newTQueueIO
|
|
||||||
w <- newTVarIO 0
|
|
||||||
|
|
||||||
p1 <- ContT $ withAsync $ forever do
|
|
||||||
pause @'Seconds 0.001
|
|
||||||
x <- randomIO @Word64
|
|
||||||
atomically do
|
|
||||||
writeTQueue q x
|
|
||||||
modifyTVar w succ
|
|
||||||
|
|
||||||
p2 <- ContT $ withAsync $ do
|
|
||||||
atomically $ fix \next -> do
|
|
||||||
e <- readTQueue q
|
|
||||||
if (e == 0xDEADF00D) then none else next
|
|
||||||
|
|
||||||
p3 <- ContT $ withAsync $ do
|
|
||||||
pause @'Seconds 10
|
|
||||||
|
|
||||||
waitAnyCatchCancel [p1,p2,p3]
|
|
||||||
|
|
||||||
s <- atomically $ STM.flushTQueue q
|
|
||||||
n <- readTVarIO w
|
|
||||||
|
|
||||||
liftIO $ print $ "so?" <+> pretty n <+> pretty (length s)
|
|
||||||
|
|
||||||
setupLogger
|
setupLogger
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue