packages feed

haskoin-store 0.49.0 → 0.50.0

raw patch · 6 files changed

+89/−23 lines, 6 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Haskoin.Store: [cacheThreads] :: CacheConfig -> !CacheThreads
+ Haskoin.Store: [storeConfCacheThreads] :: StoreConfig -> !Int
+ Haskoin.Store.Cache: [cacheThreads] :: CacheConfig -> !CacheThreads
+ Haskoin.Store.Cache: newCacheThreads :: MonadIO m => Int -> m CacheThreads
+ Haskoin.Store.Manager: [storeConfCacheThreads] :: StoreConfig -> !Int
- Haskoin.Store: CacheConfig :: !Connection -> !Int -> !Integer -> !Chain -> !Int -> !Int -> !Maybe CacheMetrics -> CacheConfig
+ Haskoin.Store: CacheConfig :: !Connection -> !Int -> !Integer -> !Chain -> !Int -> !Int -> !Maybe CacheMetrics -> !CacheThreads -> CacheConfig
- Haskoin.Store: StoreConfig :: !Int -> ![HostPort] -> !Bool -> !FilePath -> !Network -> !Maybe String -> !Word32 -> !Word32 -> !Int -> !Integer -> !Bool -> !Bool -> !NominalDiffTime -> !NominalDiffTime -> !SockAddr -> WithConnection -> !Int -> !Int -> !Maybe Store -> StoreConfig
+ Haskoin.Store: StoreConfig :: !Int -> ![HostPort] -> !Bool -> !FilePath -> !Network -> !Maybe String -> !Word32 -> !Word32 -> !Int -> !Integer -> !Bool -> !Bool -> !NominalDiffTime -> !NominalDiffTime -> !SockAddr -> WithConnection -> !Int -> !Int -> !Maybe Store -> !Int -> StoreConfig
- Haskoin.Store.Cache: CacheConfig :: !Connection -> !Int -> !Integer -> !Chain -> !Int -> !Int -> !Maybe CacheMetrics -> CacheConfig
+ Haskoin.Store.Cache: CacheConfig :: !Connection -> !Int -> !Integer -> !Chain -> !Int -> !Int -> !Maybe CacheMetrics -> !CacheThreads -> CacheConfig
- Haskoin.Store.Manager: StoreConfig :: !Int -> ![HostPort] -> !Bool -> !FilePath -> !Network -> !Maybe String -> !Word32 -> !Word32 -> !Int -> !Integer -> !Bool -> !Bool -> !NominalDiffTime -> !NominalDiffTime -> !SockAddr -> WithConnection -> !Int -> !Int -> !Maybe Store -> StoreConfig
+ Haskoin.Store.Manager: StoreConfig :: !Int -> ![HostPort] -> !Bool -> !FilePath -> !Network -> !Maybe String -> !Word32 -> !Word32 -> !Int -> !Integer -> !Bool -> !Bool -> !NominalDiffTime -> !NominalDiffTime -> !SockAddr -> WithConnection -> !Int -> !Int -> !Maybe Store -> !Int -> StoreConfig

Files

CHANGELOG.md view
@@ -4,6 +4,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html) +## 0.50.0+### Added+- Limit number of simultaneous xpubs being cached.+ ## 0.49.0 ### Changed - Improve conduit merging algorithm.
app/Main.hs view
@@ -82,6 +82,7 @@     , configWebRequests     :: !Int     , configWebReqTimeout   :: !Int     , configWebPriceGet     :: !Int+    , configCacheThreads    :: !Int     }  instance Default Config where@@ -116,6 +117,7 @@                  , configWebRequests     = defWebRequests                  , configWebReqTimeout   = defWebReqTimeout                  , configWebPriceGet     = defWebPriceGet+                 , configCacheThreads    = defCacheThreads                  }  defEnv :: MonadIO m => String -> a -> (String -> Maybe a) -> m a@@ -275,6 +277,11 @@     defEnv "WEB_REQUESTS" 32 readMaybe {-# NOINLINE defWebRequests #-} +defCacheThreads :: Int+defCacheThreads = unsafePerformIO $+    defEnv "CACHE_THREADS" 8 readMaybe+{-# NOINLINE defCacheThreads #-}+ defWebReqTimeout :: Int defWebReqTimeout = unsafePerformIO $     defEnv "WEB_REQ_TIMEOUT" (45 * 1000 * 1000) readMaybe@@ -557,6 +564,13 @@         <> help "How often to retrieve price information"         <> showDefault         <> value (configWebPriceGet def)+    configCacheThreads <-+        option auto $+        metavar "INT"+        <> long "cache-threads"+        <> help "Number of simultaneous xpub caching threads"+        <> showDefault+        <> value (configCacheThreads def)     pure         Config             { configWebLimits = WebLimits {..}@@ -636,6 +650,7 @@            , configWebRequests = wreqs            , configWebReqTimeout = wtimeout            , configWebPriceGet = wpget+           , configCacheThreads = cth            } =     runStderrLoggingT . filterLogger l . with_stats $ \stats -> do         $(logInfoS) "Main" $@@ -665,6 +680,7 @@                     , storeConfCacheRefresh = crefresh                     , storeConfCacheRetryDelay = cretrydelay                     , storeConfStats = stats+                    , storeConfCacheThreads = cth                     }         withStore scfg $ \st ->             runWeb
haskoin-store.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: a206136ca02c8f998e0567b78de9de9f7b2d2a99ab278d1d62f5c1b193b9e2e2+-- hash: 5b36767c6735c36f43dfb4f75547a52955c10cde6bd527c536bdc387d03d6482  name:           haskoin-store-version:        0.49.0+version:        0.50.0 synopsis:       Storage and index for Bitcoin and Bitcoin Cash description:    Please see the README on GitHub at <https://github.com/haskoin/haskoin-store#readme> category:       Bitcoin, Finance, Network
src/Haskoin/Store/Cache.hs view
@@ -15,6 +15,7 @@     , CacheT     , CacheError(..)     , newCacheMetrics+    , newCacheThreads     , withCache     , connectRedis     , blockRefScore@@ -93,8 +94,9 @@ import           System.Random               (randomIO, randomRIO) import           UnliftIO                    (Exception, MonadIO, MonadUnliftIO,                                               TQueue, TVar, async, atomically,-                                              bracket, liftIO, link, readTQueue,-                                              readTVar, throwIO, withAsync,+                                              bracket, liftIO, link, modifyTVar,+                                              newTVarIO, readTQueue, readTVar,+                                              throwIO, wait, withAsync,                                               writeTQueue, writeTVar) import           UnliftIO.Concurrent         (threadDelay) @@ -115,8 +117,14 @@     , cacheRefresh    :: !Int -- millisenconds     , cacheRetryDelay :: !Int -- microseconds     , cacheMetrics    :: !(Maybe CacheMetrics)+    , cacheThreads    :: !CacheThreads     } +type CacheThreads = TVar Int++newCacheThreads :: MonadIO m => Int -> m CacheThreads+newCacheThreads = newTVarIO+ data CacheMetrics = CacheMetrics     { cacheHits            :: !Metrics.Counter     , cacheMisses          :: !Metrics.Counter@@ -226,7 +234,7 @@             Just cfg -> lift (runReaderT (getXPubTxs xpub limits) cfg)     xPubTxCount xpub =         ask >>= \case-            Nothing -> lift (xPubTxCount xpub)+            Nothing  -> lift (xPubTxCount xpub)             Just cfg -> lift (runReaderT (getXPubTxCount xpub) cfg)     getMaxGap = lift getMaxGap     getInitialGap = lift getInitialGap@@ -244,6 +252,9 @@ utxoPfx :: ByteString utxoPfx = "u" +idxPfx :: ByteString+idxPfx = "i"+ getXPubTxs ::        (MonadUnliftIO m, MonadLoggerIO m, StoreReadExtra m)     => XPubSpec -> Limits -> CacheX m [TxRef]@@ -679,21 +690,21 @@ newXPubC ::        (MonadUnliftIO m, MonadLoggerIO m, StoreReadExtra m)     => XPubSpec -> [XPubBal] -> CacheX m ()-newXPubC xpub bals =-    should_index >>= \i ->+newXPubC xpub bals = should_index >>= \i ->     if i     then do-        incrementCounter cacheMisses-        withMetrics cacheIndexTime index+        a <- async $ do+            incrementCounter cacheMisses+            withMetrics cacheIndexTime index+        wait a     else incrementCounter cacheIgnore   where     op XPubUnspent {xPubUnspent = u} = (unspentPoint u, unspentBlock u)-    should_index = do-        x <- asks cacheMin+    should_index = asks cacheMin >>= \x ->         if x <= lenNotNull bals-            then inSync-            else return False-    index = do+        then is_indexing >>= \y -> if y then return False else inSync+        else return False+    index = bracket set_index unset_index $ \(x, y) -> when (x && y) $ do         xpubtxt <- xpubText xpub         $(logDebugS) "Cache" $             "Caching " <> xpubtxt <> ": " <> cs (show (length bals)) <>@@ -715,6 +726,35 @@             e <- redisAddXPubTxs xpub xtxs             return $ b >> c >> d >> e >> return ()         $(logDebugS) "Cache" $ "Cached " <> xpubtxt+    is_indexing = runRedis (Redis.exists key)+    key = idxPfx <> encode xpub+    get_thread = do+        v <- asks cacheThreads+        atomically $ do+            x <- readTVar v+            if x <= 0+                then return False+                else modifyTVar v (subtract 1) >> return True+    put_thread = do+        v <- asks cacheThreads+        atomically $ modifyTVar v (+1)+    unset_index (x, y) = do+        when x put_thread+        when y . void . runRedis $ Redis.del [key]+    set_index =+        let opts = Redis.SetOpts+                   { Redis.setSeconds = Just 600+                   , Redis.setMilliseconds = Nothing+                   , Redis.setCondition = Just Redis.Nx+                   }+            red = Redis.setOpts key "1" opts+        in get_thread >>= \case+            True -> do+                conn <- asks cacheConn+                liftIO (Redis.runRedis conn red) >>= \case+                    Right _ -> return (True, True)+                    Left _  -> return (True, False)+            False -> return (False, False)  inSync :: (MonadUnliftIO m, MonadLoggerIO m, StoreReadExtra m)        => CacheX m Bool@@ -1282,7 +1322,7 @@     net <- lift getNetwork     let suffix = case xPubDeriveType xpub of                      DeriveNormal -> ""-                     DeriveP2SH -> "/p2sh"+                     DeriveP2SH   -> "/p2sh"                      DeriveP2WPKH -> "/p2wpkh"     return . cs $ suffix <> xPubExport net (xPubSpecKey xpub) 
src/Haskoin/Store/Manager.hs view
@@ -36,16 +36,17 @@                                                 blockStoreTxSTM, withBlockStore) import           Haskoin.Store.Cache           (CacheConfig (..), CacheWriter,                                                 cacheNewBlock, cacheWriter,-                                                connectRedis, newCacheMetrics)+                                                connectRedis, newCacheMetrics,+                                                newCacheThreads) import           Haskoin.Store.Common          (StoreEvent (..)) import           Haskoin.Store.Database.Reader (DatabaseReader (..),                                                 DatabaseReaderT,                                                 withDatabaseReader)-import           Network.Socket                (SockAddr (..)) import           NQE                           (Inbox, Process (..), Publisher,                                                 publishSTM, receive,                                                 withProcess, withPublisher,                                                 withSubscription)+import           Network.Socket                (SockAddr (..)) import qualified System.Metrics                as Metrics (Store) import           UnliftIO                      (MonadIO, MonadUnliftIO, STM,                                                 atomically, link, withAsync)@@ -102,6 +103,8 @@       -- ^ delay in microseconds to retry getting cache lock         , storeConfStats           :: !(Maybe Metrics.Store)       -- ^ stats store+        , storeConfCacheThreads    :: !Int+      -- ^ how many caching threads         }  withStore :: (MonadLoggerIO m, MonadUnliftIO m)@@ -187,14 +190,15 @@             mapM newCacheMetrics (storeConfStats cfg) >>= \metrics ->             connectRedis redisurl >>= \conn ->             withSubscription pub $ \evts ->-            withProcess (f conn metrics) $ \p ->-            cacheWriterProcesses crefresh evts (getProcessMailbox p) $-            action (Just (c conn metrics))+            newCacheThreads (storeConfCacheThreads cfg) >>= \cth ->+            let conf = c conn metrics cth+            in  withProcess (f conf) $ \p ->+                cacheWriterProcesses crefresh evts (getProcessMailbox p) $ do+                action (Just conf)   where     crefresh = storeConfCacheRefresh cfg-    f conn metrics cwinbox =-        runReaderT (cacheWriter (c conn metrics) cwinbox) db-    c conn metrics =+    f conf cwinbox = runReaderT (cacheWriter conf cwinbox) db+    c conn metrics cth =         CacheConfig            { cacheConn = conn            , cacheMin = storeConfCacheMin cfg@@ -203,6 +207,7 @@            , cacheRefresh = storeConfCacheRefresh cfg            , cacheRetryDelay = storeConfCacheRetryDelay cfg            , cacheMetrics = metrics+           , cacheThreads = cth            }  cacheWriterProcesses :: MonadUnliftIO m
test/Haskoin/StoreSpec.hs view
@@ -99,6 +99,7 @@               , storeConfCacheRefresh = 750               , storeConfCacheRetryDelay = 100000               , storeConfStats = Nothing+              , storeConfCacheThreads = 8               }     withStore cfg $ \Store {..} ->         withSubscription storePublisher $ \sub ->