-
Notifications
You must be signed in to change notification settings - Fork 217
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
cache latest checkpoint in-memory to avoid deserializing and reserializing it too often #2161
Conversation
:: W.WalletId | ||
-> SqlPersistT IO (Maybe (W.Wallet s)) | ||
selectLatestCheckpoint wid = | ||
liftIO (readIORef cache) >>= maybe fromDatabase (pure . Just) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The cache doesn't live in atomically
, in contrast to the rest of the DB layer. Couldn't this lead to race-conditions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There can only be a single execution thread in atomically
(constructed with an MVar lock), hence the use of a mere IORef here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was imagining something more like:
----------------------------------------------------------------------> time
1: putCheckpoint cp1
2: selectLatest >>= f >>= putCheckpoint
selectLatest >>= g >>= putCheckpoint
- Updates cache, but operation is cancelled before the DB is updated. Cache and DB diverges.
- DB cp will be overwritten by the cached checkpoint the next time it is modified
But I guess the worst thing that can happen is that a somehow-failing putCheckpoint
will end up succeeding 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updates cache, but operation is cancelled before the DB is updated. Cache and DB diverges.
Cache is updated after the put operation has succeeded though. If it doesn't succeed, the cache isn't updated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, Matthias pointed out that "We create an illusion of transaction by having a top-level MVar lock.", so there shouldn't be Sqlite transactions being run and then somehow cancelled.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also added some notes in the code about this in place where the cache is created.
4a1a509
to
bf99652
Compare
lib/shelley/0.2-percent-rnd.timelog
Outdated
1600712574.291298178s 5000 | ||
1600712574.365636401s 6000 | ||
1600712574.503498748s 7000 | ||
1600712574.663584257s 8000 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whoops. Sounds like I a wrong git add lib
indeed :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice speedup. LGTM.
clearCache wid = liftIO $ modifyIORef cache $ Map.delete wid | ||
|
||
let writeCache :: W.WalletId -> W.Wallet s -> SqlPersistT IO () | ||
writeCache wid cp = liftIO $ modifyIORef cache $ Map.alter alter wid |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a chance of buildup of thunks here? Though I suppose we'd notice that when testing this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thought of it and:
- Map is strict, so values are evaluated before they are put in the Map
- We never just write in the cache without reading and evaluating data from it first.
So no, I don't think there's any chance that large thunks will be built here. I could switch to modifyIORef'
for the tranquility of mind, we don't need the lazyness anyway since we have in principle already evaluated the cache to WHNF (and that's actually part of why we want to cache it!)
bf99652
to
56cef9b
Compare
bors try |
tryBuild failed: |
…lizing too often This little change has some drastic performance improvements on various tasks of the wallet: ``` Wallet Overview number of addresses: 29209 number of transactions: 48819 number of utxos: 2778 UTxOs Bench | No Cache | With Cache --- | -- | --- restoreTime | 63min | 22min readWalletTime | 715ms | 53.70 ms listAddressesTime | 1.863s | 2.169 ms listTransactionsTime | 75.72s | 12.68 s importOneAddressTime | 2.526s | 260.4 ms importManyAddressesTime | 3.104s | 1.690 s estimateFeesTime | 2.103s | 63.11 ms ```
56cef9b
to
98dfd2f
Compare
bors r+ |
2161: cache latest checkpoint in-memory to avoid deserializing and reserializing it too often r=KtorZ a=KtorZ # Issue Number <!-- Put here a reference to the issue this PR relates to and which requirements it tackles --> # Overview <!-- Detail in a few bullet points the work accomplished in this PR --> This little change has some drastic performance improvements on various tasks of the wallet: ``` Wallet Overview number of addresses: 29209 number of transactions: 48819 number of utxos: 2778 UTxOs Bench | No Cache | With Cache --- | -- | --- restoreTime | 63min | 22min readWalletTime | 715ms | 53.70 ms listAddressesTime | 1.863s | 2.169 ms listTransactionsTime | 75.72s | 12.68 s importOneAddressTime | 2.526s | 260.4 ms importManyAddressesTime | 3.104s | 1.690 s estimateFeesTime | 2.103s | 63.11 ms ``` This cache approach however supposes that there's only a single wallet per database, which is the case and has been the case for a long time now. I'll remove the WalletId from the database interface in a next commit to clean things up a bit. # Comments <!-- Additional comments or screenshots to attach if any --> <!-- Don't forget to: ✓ Self-review your changes to make sure nothing unexpected slipped through ✓ Assign yourself to the PR ✓ Assign one or several reviewer(s) ✓ Once created, link this PR to its corresponding ticket ✓ Assign the PR to a corresponding milestone ✓ Acknowledge any changes required to the Wiki --> Co-authored-by: KtorZ <[email protected]>
Timed out. |
bors retry |
2161: cache latest checkpoint in-memory to avoid deserializing and reserializing it too often r=KtorZ a=KtorZ # Issue Number <!-- Put here a reference to the issue this PR relates to and which requirements it tackles --> # Overview <!-- Detail in a few bullet points the work accomplished in this PR --> This little change has some drastic performance improvements on various tasks of the wallet: ``` Wallet Overview number of addresses: 29209 number of transactions: 48819 number of utxos: 2778 UTxOs Bench | No Cache | With Cache --- | -- | --- restoreTime | 63min | 22min readWalletTime | 715ms | 53.70 ms listAddressesTime | 1.863s | 2.169 ms listTransactionsTime | 75.72s | 12.68 s importOneAddressTime | 2.526s | 260.4 ms importManyAddressesTime | 3.104s | 1.690 s estimateFeesTime | 2.103s | 63.11 ms ``` This cache approach however supposes that there's only a single wallet per database, which is the case and has been the case for a long time now. I'll remove the WalletId from the database interface in a next commit to clean things up a bit. # Comments <!-- Additional comments or screenshots to attach if any --> <!-- Don't forget to: ✓ Self-review your changes to make sure nothing unexpected slipped through ✓ Assign yourself to the PR ✓ Assign one or several reviewer(s) ✓ Once created, link this PR to its corresponding ticket ✓ Assign the PR to a corresponding milestone ✓ Acknowledge any changes required to the Wiki --> Co-authored-by: KtorZ <[email protected]>
Build failed: Log-limit exceeded, perhaps due to running out of faucet funds, which should be fixed on recent master. |
This was introduced as a hotfix for the Daedalus flight release of April 2019. By now, we have got rid of the old cardano-sl implementation for which this was causing an issue and can get back to 'normal'. I also removed the associated test.
98dfd2f
to
6d61c8a
Compare
bors r+ |
2161: cache latest checkpoint in-memory to avoid deserializing and reserializing it too often r=KtorZ a=KtorZ # Issue Number <!-- Put here a reference to the issue this PR relates to and which requirements it tackles --> # Overview <!-- Detail in a few bullet points the work accomplished in this PR --> This little change has some drastic performance improvements on various tasks of the wallet: ``` Wallet Overview number of addresses: 29209 number of transactions: 48819 number of utxos: 2778 UTxOs Bench | No Cache | With Cache --- | -- | --- restoreTime | 63min | 22min readWalletTime | 715ms | 53.70 ms listAddressesTime | 1.863s | 2.169 ms listTransactionsTime | 75.72s | 12.68 s importOneAddressTime | 2.526s | 260.4 ms importManyAddressesTime | 3.104s | 1.690 s estimateFeesTime | 2.103s | 63.11 ms ``` This cache approach however supposes that there's only a single wallet per database, which is the case and has been the case for a long time now. I'll remove the WalletId from the database interface in a next commit to clean things up a bit. # Comments <!-- Additional comments or screenshots to attach if any --> <!-- Don't forget to: ✓ Self-review your changes to make sure nothing unexpected slipped through ✓ Assign yourself to the PR ✓ Assign one or several reviewer(s) ✓ Once created, link this PR to its corresponding ticket ✓ Assign the PR to a corresponding milestone ✓ Acknowledge any changes required to the Wiki --> Co-authored-by: KtorZ <[email protected]>
Build failed:
|
bors merge |
Build succeeded: |
Issue Number
Overview
This little change has some drastic performance improvements on
various tasks of the wallet:
This cache approach however supposes that there's only a single wallet
per database, which is the case and has been the case for a long time
now. I'll remove the WalletId from the database interface in a next
commit to clean things up a bit.
Comments