Skip to content
This repository was archived by the owner on Dec 2, 2024. It is now read-only.

Commit e4062bc

Browse files
author
Evgenii Akentev
authored
SCP-3445: fix chain index blocking (#386)
* [chain-index]: replace chain index state's MVar with TVar * [chain-index]: add sqlite connection pool
1 parent 9ab49d8 commit e4062bc

File tree

29 files changed

+172
-104
lines changed

29 files changed

+172
-104
lines changed

freer-extras/freer-extras.cabal

+2
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ library
4949
mtl -any,
5050
openapi3 -any,
5151
prettyprinter -any,
52+
resource-pool -any,
5253
sqlite-simple -any,
5354
streaming -any,
5455
text -any,
@@ -75,5 +76,6 @@ test-suite freer-extras-test
7576
freer-extras -any,
7677
freer-simple -any,
7778
lens -any,
79+
resource-pool -any,
7880
semigroups -any,
7981
sqlite-simple -any,

freer-extras/src/Control/Monad/Freer/Extras/Beam.hs

+32-30
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,41 @@
1-
{-# LANGUAGE ConstraintKinds #-}
2-
{-# LANGUAGE DataKinds #-}
3-
{-# LANGUAGE DeriveAnyClass #-}
4-
{-# LANGUAGE DerivingStrategies #-}
5-
{-# LANGUAGE FlexibleContexts #-}
6-
{-# LANGUAGE FlexibleInstances #-}
7-
{-# LANGUAGE GADTs #-}
8-
{-# LANGUAGE KindSignatures #-}
9-
{-# LANGUAGE LambdaCase #-}
10-
{-# LANGUAGE NamedFieldPuns #-}
11-
{-# LANGUAGE NumericUnderscores #-}
12-
{-# LANGUAGE OverloadedStrings #-}
13-
{-# LANGUAGE RankNTypes #-}
14-
{-# LANGUAGE StrictData #-}
15-
{-# LANGUAGE TemplateHaskell #-}
16-
{-# LANGUAGE TypeApplications #-}
17-
{-# LANGUAGE TypeOperators #-}
18-
{-# LANGUAGE ViewPatterns #-}
1+
{-# LANGUAGE ConstraintKinds #-}
2+
{-# LANGUAGE DataKinds #-}
3+
{-# LANGUAGE DeriveAnyClass #-}
4+
{-# LANGUAGE DerivingStrategies #-}
5+
{-# LANGUAGE FlexibleContexts #-}
6+
{-# LANGUAGE FlexibleInstances #-}
7+
{-# LANGUAGE GADTs #-}
8+
{-# LANGUAGE KindSignatures #-}
9+
{-# LANGUAGE LambdaCase #-}
10+
{-# LANGUAGE MultiParamTypeClasses #-}
11+
{-# LANGUAGE NamedFieldPuns #-}
12+
{-# LANGUAGE NumericUnderscores #-}
13+
{-# LANGUAGE OverloadedStrings #-}
14+
{-# LANGUAGE RankNTypes #-}
15+
{-# LANGUAGE StrictData #-}
16+
{-# LANGUAGE TemplateHaskell #-}
17+
{-# LANGUAGE TypeApplications #-}
18+
{-# LANGUAGE TypeFamilies #-}
19+
{-# LANGUAGE TypeOperators #-}
20+
{-# LANGUAGE ViewPatterns #-}
1921

2022
module Control.Monad.Freer.Extras.Beam where
2123

2224
import Cardano.BM.Data.Tracer (ToObject (..))
2325
import Cardano.BM.Trace (Trace, logDebug)
2426
import Control.Concurrent (threadDelay)
25-
import Control.Exception (try)
27+
import Control.Exception (Exception, throw, try)
2628
import Control.Monad (guard)
2729
import Control.Monad.Freer (Eff, LastMember, Member, type (~>))
28-
import Control.Monad.Freer.Error (Error, throwError)
2930
import Control.Monad.Freer.Extras.Pagination (Page (..), PageQuery (..), PageSize (..))
3031
import Control.Monad.Freer.Reader (Reader, ask)
3132
import Control.Monad.Freer.TH (makeEffect)
3233
import Data.Aeson (FromJSON, ToJSON)
3334
import Data.Foldable (traverse_)
3435
import Data.List.NonEmpty qualified as L
3536
import Data.Maybe (isJust, listToMaybe)
37+
import Data.Pool (Pool)
38+
import Data.Pool qualified as Pool
3639
import Data.Text (Text)
3740
import Data.Text qualified as Text
3841
import Database.Beam (Beamable, DatabaseEntity, FromBackendRow, Identity, MonadIO (liftIO), Q, QBaseScope, QExpr,
@@ -58,6 +61,8 @@ newtype BeamError =
5861
deriving stock (Eq, Show, Generic)
5962
deriving anyclass (FromJSON, ToJSON, ToObject)
6063

64+
instance Exception BeamError
65+
6166
instance Pretty BeamError where
6267
pretty = \case
6368
SqlError s -> "SqlError (via Beam)" <> colon <+> pretty s
@@ -126,8 +131,7 @@ instance Semigroup (BeamEffect ()) where
126131
handleBeam ::
127132
forall effs.
128133
( LastMember IO effs
129-
, Member (Error BeamError) effs
130-
, Member (Reader Sqlite.Connection) effs
134+
, Member (Reader (Pool Sqlite.Connection)) effs
131135
)
132136
=> Trace IO BeamLog
133137
-> BeamEffect
@@ -176,30 +180,28 @@ handleBeam trace eff = runBeam trace $ execute eff
176180
runBeam ::
177181
forall effs.
178182
( LastMember IO effs
179-
, Member (Error BeamError) effs
180-
, Member (Reader Sqlite.Connection) effs
183+
, Member (Reader (Pool Sqlite.Connection)) effs
181184
)
182185
=> Trace IO BeamLog
183186
-> SqliteM
184187
~> Eff effs
185188
runBeam trace action = do
186-
conn <- ask @Sqlite.Connection
187-
loop conn ( 5 :: Int )
189+
pool <- ask @(Pool Sqlite.Connection)
190+
liftIO $ Pool.withResource pool $ \conn -> loop conn ( 5 :: Int )
188191
where
189192
loop conn retries = do
190193
let traceSql = logDebug trace . SqlLog
191-
resultEither <- liftIO $ try $ Sqlite.withTransaction conn $ runBeamSqliteDebug traceSql conn action
194+
resultEither <- try $ Sqlite.withTransaction conn $ runBeamSqliteDebug traceSql conn action
192195
case resultEither of
193196
-- 'Database.SQLite.Simple.ErrorError' corresponds to an SQL error or
194197
-- missing database. When this exception is raised, we suppose it's
195198
-- because the another transaction was already running.
196199
Left (Sqlite.SQLError Sqlite.ErrorError _ _) | retries > 0 -> do
197-
liftIO $ threadDelay 100_000
200+
threadDelay 100_000
198201
loop conn (retries - 1)
199202
-- We handle and rethrow errors other than
200203
-- 'Database.SQLite.Simple.ErrorError'.
201-
Left e -> do
202-
throwError $ SqlError $ Text.pack $ show e
204+
Left e -> throw $ SqlError $ Text.pack $ show e
203205
Right v -> return v
204206

205207
makeEffect ''BeamEffect

freer-extras/test/Control/Monad/Freer/Extras/BeamSpec.hs

+12-8
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
{-# LANGUAGE FlexibleInstances #-}
77
{-# LANGUAGE GADTs #-}
88
{-# LANGUAGE ImpredicativeTypes #-}
9+
{-# LANGUAGE NumericUnderscores #-}
910
{-# LANGUAGE OverloadedStrings #-}
1011
{-# LANGUAGE TypeFamilies #-}
1112
{-# LANGUAGE UndecidableInstances #-}
@@ -24,6 +25,8 @@ import Control.Tracer (nullTracer)
2425
import Data.Int (Int16)
2526
import Data.Kind (Constraint)
2627
import Data.List (sort)
28+
import Data.Pool (Pool)
29+
import Data.Pool qualified as Pool
2730
import Data.Semigroup.Generic (GenericSemigroupMonoid (..))
2831
import Data.Set qualified as Set
2932
import Database.Beam (Beamable, Columnar, Database, DatabaseSettings, FromBackendRow, Generic, MonadIO (liftIO), Q,
@@ -182,27 +185,28 @@ selectAllPages pq q = do
182185

183186
runBeamEffectInGenTestDb
184187
:: Set Int
185-
-> Eff '[BeamEffect, Error BeamError, Reader Sqlite.Connection, IO] a
188+
-> Eff '[BeamEffect, Error BeamError, Reader (Pool Sqlite.Connection), IO] a
186189
-> (a -> PropertyT IO ())
187190
-> PropertyT IO ()
188191
runBeamEffectInGenTestDb items effect runTest = do
189-
result <- liftIO $ Sqlite.withConnection ":memory:" $ \conn -> do
190-
Sqlite.runBeamSqlite conn $ do
192+
pool <- liftIO $ Pool.createPool (Sqlite.open ":memory:") Sqlite.close 1 1_000_000 1
193+
result <- liftIO $ do
194+
Pool.withResource pool $ \conn -> Sqlite.runBeamSqlite conn $ do
191195
autoMigrate Sqlite.migrationBackend checkedSqliteDb
192196
runInsert $ insertOnConflict (testRows db) (insertValues $ IntegerRow . fromIntegral <$> Set.toList items) anyConflict onConflictDoNothing
193-
liftIO $ runBeamEffect conn effect
197+
runBeamEffect pool effect
194198

195199
case result of
196200
Left _ -> Hedgehog.assert False
197201
Right r -> runTest r
198202

199203
runBeamEffect
200-
:: Sqlite.Connection
201-
-> Eff '[BeamEffect, Error BeamError, Reader Sqlite.Connection, IO] a
204+
:: Pool Sqlite.Connection
205+
-> Eff '[BeamEffect, Error BeamError, Reader (Pool Sqlite.Connection), IO] a
202206
-> IO (Either BeamError a)
203-
runBeamEffect conn effect = do
207+
runBeamEffect pool effect = do
204208
effect
205209
& interpret (handleBeam nullTracer)
206210
& runError
207-
& runReader conn
211+
& runReader pool
208212
& runM

nix/pkgs/haskell/materialized-darwin/.plan.nix/freer-extras.nix

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

nix/pkgs/haskell/materialized-darwin/.plan.nix/plutus-chain-index-core.nix

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

nix/pkgs/haskell/materialized-darwin/.plan.nix/plutus-chain-index.nix

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

nix/pkgs/haskell/materialized-darwin/.plan.nix/plutus-example.nix

+4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

nix/pkgs/haskell/materialized-darwin/.plan.nix/plutus-pab-executables.nix

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

nix/pkgs/haskell/materialized-darwin/.plan.nix/plutus-pab.nix

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

nix/pkgs/haskell/materialized-linux/.plan.nix/freer-extras.nix

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

nix/pkgs/haskell/materialized-linux/.plan.nix/plutus-chain-index-core.nix

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

nix/pkgs/haskell/materialized-linux/.plan.nix/plutus-chain-index.nix

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

nix/pkgs/haskell/materialized-linux/.plan.nix/plutus-pab-executables.nix

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

nix/pkgs/haskell/materialized-linux/.plan.nix/plutus-pab.nix

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

nix/pkgs/haskell/materialized-windows/.plan.nix/freer-extras.nix

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

nix/pkgs/haskell/materialized-windows/.plan.nix/plutus-chain-index-core.nix

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

nix/pkgs/haskell/materialized-windows/.plan.nix/plutus-chain-index.nix

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)