wip, respect only polled refchans

This commit is contained in:
Dmitry Zuikov 2023-07-15 06:08:56 +03:00
parent 476ecddb6d
commit 42be590baa
4 changed files with 101 additions and 33 deletions

View File

@ -105,7 +105,8 @@ instance ForRefChans e => Serialise (RefChanHead e)
data RefChanHeadAdapter e m = data RefChanHeadAdapter e m =
RefChanHeadAdapter RefChanHeadAdapter
{ refChanHeadOnHead :: RefChanHeadBlockTran e -> m () { refChanHeadOnHead :: RefChanId e -> RefChanHeadBlockTran e -> m ()
, refChanHeadSubscribed :: RefChanId e -> m Bool
} }
refChanHeadProto :: forall e s m . ( MonadIO m refChanHeadProto :: forall e s m . ( MonadIO m
@ -135,9 +136,10 @@ refChanHeadProto self adapter msg = do
case msg of case msg of
RefChanHead chan pkt -> do RefChanHead chan pkt -> do
guard =<< lift (refChanHeadSubscribed adapter chan)
trace $ "RefChanHead" <+> pretty self <+> pretty (AsBase58 chan) trace $ "RefChanHead" <+> pretty self <+> pretty (AsBase58 chan)
-- FIXME: check-chan-is-listened -- FIXME: check-chan-is-listened
lift $ refChanHeadOnHead adapter pkt lift $ refChanHeadOnHead adapter chan pkt
RefChanGetHead _ -> do RefChanGetHead _ -> do
-- прочитать ссылку -- прочитать ссылку

View File

@ -5,33 +5,37 @@ module Brains where
import HBS2.Prelude.Plated import HBS2.Prelude.Plated
import HBS2.Clock import HBS2.Clock
import HBS2.Data.Types.Refs
import HBS2.Net.Proto import HBS2.Net.Proto
import HBS2.Hash import HBS2.Hash
import HBS2.Base58
import HBS2.Net.IP.Addr import HBS2.Net.IP.Addr
import HBS2.Net.Auth.Credentials
import HBS2.System.Logger.Simple import HBS2.System.Logger.Simple
import PeerConfig import PeerConfig
import Data.Maybe
import Control.Monad
import Control.Exception
import Control.Concurrent.STM import Control.Concurrent.STM
import Control.Concurrent.Async import Control.Exception
import Lens.Micro.Platform import Control.Monad
import Data.HashMap.Strict qualified as HashMap
import Data.HashMap.Strict (HashMap)
import Data.List qualified as List
import Data.Cache (Cache)
import Data.Cache qualified as Cache
import Text.InterpolatedString.Perl6 (qc)
import Database.SQLite.Simple import Database.SQLite.Simple
import Database.SQLite.Simple.FromField import Database.SQLite.Simple.FromField
import System.Random (randomRIO) import Data.Cache (Cache)
import Data.Word import Data.Cache qualified as Cache
import Data.Either import Data.Either
import Data.HashMap.Strict (HashMap)
import Data.HashMap.Strict qualified as HashMap
import Data.List qualified as List
import Data.Maybe
import Data.Text qualified as Text
import Data.Word
import Lens.Micro.Platform
import System.Directory import System.Directory
import System.FilePath import System.FilePath
import System.Random (randomRIO)
import Text.InterpolatedString.Perl6 (qc)
import UnliftIO (MonadUnliftIO(..),async,race)
data PeerBrainsDb data PeerBrainsDb
@ -40,6 +44,12 @@ instance HasCfgKey PeerBrainsDb (Maybe String) where
class HasBrains e a where class HasBrains e a where
listPolledRefs :: MonadIO m => a -> String -> m [(PubKey 'Sign (Encryption e), Int)]
listPolledRefs _ _ = pure mempty
isPolledRef :: MonadIO m => a -> PubKey 'Sign (Encryption e) -> m Bool
isPolledRef _ _ = pure False
onClientTCPConnected :: MonadIO m => a -> PeerAddr e -> Word64 -> m () onClientTCPConnected :: MonadIO m => a -> PeerAddr e -> Word64 -> m ()
onClientTCPConnected _ _ = const none onClientTCPConnected _ _ = const none
@ -148,6 +158,8 @@ instance Pretty (Peer e) => HasBrains e NoBrains where
data SomeBrains e = forall a . HasBrains e a => SomeBrains a data SomeBrains e = forall a . HasBrains e a => SomeBrains a
instance HasBrains e (SomeBrains e) where instance HasBrains e (SomeBrains e) where
listPolledRefs (SomeBrains a) = listPolledRefs @e a
isPolledRef (SomeBrains a) = isPolledRef @e a
onClientTCPConnected (SomeBrains a) = onClientTCPConnected @e a onClientTCPConnected (SomeBrains a) = onClientTCPConnected @e a
getClientTCP (SomeBrains a) = getClientTCP @e a getClientTCP (SomeBrains a) = getClientTCP @e a
setActiveTCPSessions (SomeBrains a) = setActiveTCPSessions @e a setActiveTCPSessions (SomeBrains a) = setActiveTCPSessions @e a
@ -279,6 +291,23 @@ instance ( Hashable (Peer e)
setReflogProcessed b h = do setReflogProcessed b h = do
updateOP b $ insertReflogProcessed b h updateOP b $ insertReflogProcessed b h
listPolledRefs brains tp = do
liftIO $ do
let conn = view brainsDb brains
query conn [qc|select ref, interval from poll where type = ?|] (Only tp)
<&> fmap (\(r,i) -> (,i) <$> fromStringMay r )
<&> catMaybes
isPolledRef brains ref = do
liftIO do
let conn = view brainsDb brains
query @_ @(Only Int) conn [qc|
select 1 from poll
where ref = ?
limit 1
|] ( Only ( show $ pretty (AsBase58 ref) ) )
<&> isJust . listToMaybe
commitNow :: forall e m . MonadIO m commitNow :: forall e m . MonadIO m
=> BasicBrains e => BasicBrains e
-> Bool -> Bool
@ -690,6 +719,16 @@ newBasicBrains cfg = liftIO do
) )
|] |]
execute_ conn [qc|
create table if not exists poll
( ref text not null
, type text not null
, interval int not null
, primary key (ref,type)
)
|]
BasicBrains <$> newTVarIO mempty BasicBrains <$> newTVarIO mempty
<*> newTVarIO mempty <*> newTVarIO mempty
<*> Cache.newCache (Just (toTimeSpec (30 :: Timeout 'Seconds))) <*> Cache.newCache (Just (toTimeSpec (30 :: Timeout 'Seconds)))
@ -697,8 +736,12 @@ newBasicBrains cfg = liftIO do
<*> newTQueueIO <*> newTQueueIO
<*> newTQueueIO <*> newTQueueIO
runBasicBrains :: MonadIO m => BasicBrains e -> m () runBasicBrains :: forall e m . ( e ~ L4Proto, MonadUnliftIO m )
runBasicBrains brains = do => PeerConfig
-> BasicBrains e
-> m ()
runBasicBrains cfg brains = do
let pip = view brainsPipeline brains let pip = view brainsPipeline brains
let expire = view brainsExpire brains let expire = view brainsExpire brains
@ -725,6 +768,27 @@ runBasicBrains brains = do
pause @'Seconds 60 pause @'Seconds 60
updateOP brains (cleanupHashes brains) updateOP brains (cleanupHashes brains)
trace "runBasicBrains init"
let (PeerConfig syn) = cfg
let polls = catMaybes (
[ (tp,n,) <$> fromStringMay @(PubKey 'Sign (Encryption e)) (Text.unpack ref)
| ListVal @C (Key "poll" [SymbolVal tp, LitIntVal n, LitStrVal ref]) <- syn
] )
void $ async $ do
pause @'Seconds 5
forM_ polls $ \(t,mi,x) -> do
trace $ "BRAINS: poll" <+> pretty t <+> pretty (AsBase58 x) <+> pretty mi
updateOP brains $ do
let conn = view brainsDb brains
liftIO $ execute conn [qc|
insert into poll (ref,type,interval)
values (?,?,?)
on conflict do update set interval = excluded.interval
|] (show $ pretty (AsBase58 x), show $ pretty t, mi)
commitNow brains True
void $ forever do void $ forever do
pause @'Seconds 15 pause @'Seconds 15
ee <- liftIO $ Cache.toList expire ee <- liftIO $ Cache.toList expire

View File

@ -533,7 +533,7 @@ runPeer opts = U.handle (\e -> myException e
brains <- newBasicBrains @e conf brains <- newBasicBrains @e conf
brainsThread <- async $ runBasicBrains brains brainsThread <- async $ runBasicBrains conf brains
denv <- newDownloadEnv brains denv <- newDownloadEnv brains
@ -564,6 +564,7 @@ runPeer opts = U.handle (\e -> myException e
let refChanHeadAdapter = RefChanHeadAdapter let refChanHeadAdapter = RefChanHeadAdapter
{ refChanHeadOnHead = refChanOnHead rce { refChanHeadOnHead = refChanOnHead rce
, refChanHeadSubscribed = isPolledRef @e brains
} }
let pexFilt pips = do let pexFilt pips = do

View File

@ -52,8 +52,8 @@ instance Exception DataNotReady
data RefChanWorkerEnv e = data RefChanWorkerEnv e =
RefChanWorkerEnv RefChanWorkerEnv
{ _refChanWorkerEnvDownload :: DownloadEnv e { _refChanWorkerEnvDownload :: DownloadEnv e
, _refChanWorkerEnvHeadQ :: TQueue (RefChanHeadBlockTran e) , _refChanWorkerEnvHeadQ :: TQueue (RefChanId e, RefChanHeadBlockTran e)
, _refChaWorkerEnvDownload :: TVar (HashMap HashRef TimeSpec) -- таймстемп можно , _refChaWorkerEnvDownload :: TVar (HashMap HashRef (RefChanId e, TimeSpec))
} }
makeLenses 'RefChanWorkerEnv makeLenses 'RefChanWorkerEnv
@ -67,22 +67,22 @@ refChanWorkerEnv _ de = liftIO $ RefChanWorkerEnv @e de <$> newTQueueIO
<*> newTVarIO mempty <*> newTVarIO mempty
refChanOnHead :: MonadIO m => RefChanWorkerEnv e -> RefChanHeadBlockTran e -> m () refChanOnHead :: MonadIO m => RefChanWorkerEnv e -> RefChanId e -> RefChanHeadBlockTran e -> m ()
refChanOnHead env tran = do refChanOnHead env chan tran = do
atomically $ writeTQueue (view refChanWorkerEnvHeadQ env) tran atomically $ writeTQueue (view refChanWorkerEnvHeadQ env) (chan, tran)
refChanAddDownload :: forall e m . ( m ~ PeerM e IO refChanAddDownload :: forall e m . ( m ~ PeerM e IO
, MyPeer e , MyPeer e
, Block ByteString ~ ByteString , Block ByteString ~ ByteString
) )
=> RefChanWorkerEnv e -> HashRef -> m () => RefChanWorkerEnv e -> RefChanId e -> HashRef -> m ()
refChanAddDownload env r = do refChanAddDownload env chan r = do
penv <- ask penv <- ask
t <- getTimeCoarse t <- getTimeCoarse
withPeerM penv $ withDownload (_refChanWorkerEnvDownload env) withPeerM penv $ withDownload (_refChanWorkerEnvDownload env)
$ processBlock @e (fromHashRef r) $ processBlock @e (fromHashRef r)
atomically $ modifyTVar (view refChaWorkerEnvDownload env) (HashMap.insert r t) atomically $ modifyTVar (view refChaWorkerEnvDownload env) (HashMap.insert r (chan,t))
checkDownloaded :: forall m . (MonadIO m, HasStorage m, Block ByteString ~ ByteString) => HashRef -> m Bool checkDownloaded :: forall m . (MonadIO m, HasStorage m, Block ByteString ~ ByteString) => HashRef -> m Bool
checkDownloaded hr = do checkDownloaded hr = do
@ -146,28 +146,27 @@ refChanWorker env = do
now <- getTimeCoarse now <- getTimeCoarse
-- FIXME: consider-timeouts-or-leak-is-possible -- FIXME: consider-timeouts-or-leak-is-possible
rest <- forM all $ \(r,t) -> do rest <- forM all $ \(r,item@(chan,t)) -> do
here <- checkDownloaded r here <- checkDownloaded r
if here then do if here then do
refChanOnHead env (RefChanHeadBlockTran r) refChanOnHead env chan (RefChanHeadBlockTran r)
pure mempty pure mempty
else do else do
-- FIXME: fix-timeout-hardcode -- FIXME: fix-timeout-hardcode
let expired = realToFrac (toNanoSecs $ now - t) / 1e9 > 600 let expired = realToFrac (toNanoSecs $ now - t) / 1e9 > 600
if expired then pure mempty else pure [(r,t)] if expired then pure mempty else pure [(r,item)]
atomically $ writeTVar (view refChaWorkerEnvDownload env) (HashMap.fromList (mconcat rest)) atomically $ writeTVar (view refChaWorkerEnvDownload env) (HashMap.fromList (mconcat rest))
-- FIXME: in-parallel? -- FIXME: in-parallel?
refChanHeadMon = do refChanHeadMon = do
forever do forever do
RefChanHeadBlockTran hr <- atomically $ readTQueue (view refChanWorkerEnvHeadQ env) (chan, RefChanHeadBlockTran hr) <- atomically $ readTQueue (view refChanWorkerEnvHeadQ env)
-- debug $ "DROP HEAD UPDATE" <+> pretty (fromRefChanHeadBlockTran tran)
here <- checkDownloaded hr here <- checkDownloaded hr
if not here then do if not here then do
refChanAddDownload env hr refChanAddDownload env chan hr
trace $ "BLOCK IS NOT HERE" <+> pretty hr trace $ "BLOCK IS NOT HERE" <+> pretty hr
else do else do
trace $ "BLOCK IS HERE" <+> pretty hr trace $ "BLOCK IS HERE" <+> pretty hr
@ -178,7 +177,7 @@ refChanWorker env = do
case what of case what of
Nothing -> err $ "malformed head block" <+> pretty hr Nothing -> err $ "malformed head block" <+> pretty hr
Just (pk,blk) -> do Just (pk,blk) | pk == chan -> do
let rkey = RefChanHeadKey @s pk let rkey = RefChanHeadKey @s pk
sto <- getStorage sto <- getStorage
@ -205,6 +204,8 @@ refChanWorker env = do
else do else do
debug $ "LEAVING HEAD BLOCK" <+> pretty (v1, v0) debug $ "LEAVING HEAD BLOCK" <+> pretty (v1, v0)
_ -> debug "not subscribed to this refchan"
pure () pure ()
-- распаковываем блок -- распаковываем блок
-- вытаскиваем ключ из блока? -- вытаскиваем ключ из блока?