Skip to content

Commit

Permalink
Sqlite: use repsertMany instead of deleteMany+putMany
Browse files Browse the repository at this point in the history
The function repsertMany does what I thought putMany did. When there
is a conflict it updates the rows. This means that we don't need to
delete before inserting.
  • Loading branch information
rvl committed Jun 4, 2019
1 parent 1de7ed8 commit 301e360
Showing 1 changed file with 33 additions and 14 deletions.
47 changes: 33 additions & 14 deletions lib/core/src/Cardano/Wallet/DB/Sqlite.hs
Original file line number Diff line number Diff line change
Expand Up @@ -549,22 +549,41 @@ deleteTxMetas
deleteTxMetas wid = deleteWhere [ TxMetaTableWalletId ==. wid ]

-- | Add new TxMeta rows, overwriting existing ones.
putTxMetas
:: W.WalletId
-> [TxMeta]
-> SqlPersistM ()
putTxMetas wid metas = do
let txids = map txMetaTableTxId metas
deleteMany [ TxMetaTableWalletId ==. wid ] TxMetaTableTxId txids
insertMany_ metas
putTxMetas :: [TxMeta] -> SqlPersistM ()
putTxMetas metas = dbChunked repsertMany
[(TxMetaKey txMetaTableTxId txMetaTableWalletId, m) | m@TxMeta{..} <- metas]

-- | Insert multiple transactions, removing old instances first.
putTxs :: [TxId] -> [TxIn] -> [TxOut] -> SqlPersistM ()
putTxs txIds txins txouts = do
deleteMany [] TxInputTableTxId txIds
putMany txins
deleteMany [] TxOutputTableTxId txIds
putMany txouts
putTxs :: [TxIn] -> [TxOut] -> SqlPersistM ()
putTxs txins txouts = do
dbChunked repsertMany
[ (TxInKey txInputTableTxId txInputTableSourceTxId txInputTableSourceIndex, i)
| i@TxIn{..} <- txins ]
dbChunked repsertMany
[ (TxOutKey txOutputTableTxId txOutputTableIndex, o)
| o@TxOut{..} <- txouts ]

-- | Convert a single DB "updateMany" (or similar) query into multiple
-- updateMany queries with smaller lists of values.
--
-- This is to prevent too many variables appearing in the SQL statement.
-- SQLITE_MAX_VARIABLE_NUMBER is 999 by default, and we will get a
-- "too many SQL variables" exception if that is exceeded.
--
-- We choose a conservative 100 because there can be multiple variables
-- per row updated.
dbChunked :: ([a] -> SqlPersistM b) -> [a] -> SqlPersistM ()
dbChunked = chunkedM 100

-- | Given an action which takes a list of items, and a list of items, run that
-- action multiple times with the input list cut into chunks.
chunkedM
:: Monad m
=> Int -- ^ Chunk size
-> ([a] -> m b) -- ^ Action to run on values
-> [a] -- ^ The values
-> m ()
chunkedM n f = mapM_ f . chunksOf n

-- | Delete transactions that aren't referred to by either Pending or TxMeta of
-- any wallet.
Expand Down

0 comments on commit 301e360

Please sign in to comment.