-
Notifications
You must be signed in to change notification settings - Fork 90
Spike: sqlite persistence + event log rotation #1968
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
Conversation
> based on 743fc1e
> from a hacking made on #1746 (comment)
* to ensure ordering of records over time
980f156
to
21dd19a
Compare
Transaction cost differencesScript summary
|
Parties | Tx size | % max Mem | % max CPU | Min fee ₳ |
---|---|---|---|---|
1 | - | - | - | - |
2 | - | - | - | - |
3 | - | - | - | - |
5 | - | - | - | - |
10 | - | - | - | - |
40 | - | - | - | - |
Commit
transaction costs
UTxO | Tx size | % max Mem | % max CPU | Min fee ₳ |
---|---|---|---|---|
1 | - | - | - | - |
2 | - | - | - | - |
3 | - | - | - | - |
5 | - | - | - | - |
10 | - | - | - | - |
54 | - | - | - | - |
CollectCom
transaction costs
Parties | UTxO (bytes) | Tx size | % max Mem | % max CPU | Min fee ₳ |
---|---|---|---|---|---|
1 | - | - | - | - | - |
2 | - | - | - | - | - |
3 | - | - | - | - | - |
4 | - | - | - | - | - |
5 | - | - | - | - | - |
6 | - | - | - | - | - |
7 | - | - | - | - | - |
8 | - | - | - | - | - |
Cost of Increment Transaction
Parties | Tx size | % max Mem | % max CPU | Min fee ₳ |
---|---|---|---|---|
1 | - | - | ||
2 | - | - | - | - |
3 | - | - | - | - |
5 | - | - | - | - |
10 | - | |||
37 | - | - |
Cost of Decrement Transaction
Parties | Tx size | % max Mem | % max CPU | Min fee ₳ |
---|---|---|---|---|
1 | - | - | - | - |
2 | - | - | - | - |
3 | - | - | - | - |
5 | - | - | - | - |
10 | - | - | - | - |
40 | - | - | - | - |
Close
transaction costs
Parties | Tx size | % max Mem | % max CPU | Min fee ₳ |
---|---|---|---|---|
1 | - | - | - | - |
2 | - | - | - | - |
3 | - | - | - | - |
5 | - | - | - | - |
10 | - | - | - | - |
34 | - | - | - | - |
Contest
transaction costs
Parties | Tx size | % max Mem | % max CPU | Min fee ₳ |
---|---|---|---|---|
1 | - | - | - | - |
2 | - | - | - | - |
3 | - | - | - | - |
5 | - | - | - | - |
10 | - | - | - | - |
27 | - | - | - | - |
FanOut
transaction costs
UTxO, Parties | UTxO (bytes) | Tx size | % max Mem | % max CPU | Min fee ₳ |
---|---|---|---|---|---|
(0, 10) | - | - | - | - | - |
(1, 10) | - | - | - | - | - |
(5, 10) | - | - | - | - | - |
(10, 10) | - | - | - | - | - |
(20, 10) | - | - | - | - | - |
(37, 10) | - | - | - | - | - |
Transaction costsSizes and execution budgets for Hydra protocol transactions. Note that unlisted parameters are currently using
Script summary
|
Parties | Tx size | % max Mem | % max CPU | Min fee ₳ |
---|---|---|---|---|
1 | 6094 | 10.80 | 3.35 | 0.53 |
2 | 6292 | 13.26 | 4.11 | 0.56 |
3 | 6499 | 15.59 | 4.83 | 0.60 |
5 | 6898 | 19.98 | 6.17 | 0.66 |
10 | 7904 | 31.18 | 9.61 | 0.82 |
40 | 13935 | 98.36 | 30.21 | 1.78 |
Commit
transaction costs
This uses ada-only outputs for better comparability.
UTxO | Tx size | % max Mem | % max CPU | Min fee ₳ |
---|---|---|---|---|
1 | 561 | 2.44 | 1.16 | 0.20 |
2 | 741 | 3.38 | 1.73 | 0.22 |
3 | 920 | 4.36 | 2.33 | 0.24 |
5 | 1280 | 6.41 | 3.60 | 0.28 |
10 | 2173 | 12.13 | 7.25 | 0.40 |
54 | 10059 | 98.61 | 68.52 | 1.88 |
CollectCom
transaction costs
Parties | UTxO (bytes) | Tx size | % max Mem | % max CPU | Min fee ₳ |
---|---|---|---|---|---|
1 | 57 | 525 | 26.47 | 7.60 | 0.44 |
2 | 113 | 636 | 35.90 | 10.22 | 0.54 |
3 | 171 | 747 | 44.51 | 12.70 | 0.63 |
4 | 227 | 858 | 50.69 | 14.55 | 0.70 |
5 | 284 | 969 | 65.60 | 18.53 | 0.86 |
6 | 338 | 1085 | 75.46 | 21.33 | 0.96 |
7 | 392 | 1192 | 85.08 | 24.03 | 1.06 |
8 | 451 | 1303 | 84.45 | 24.23 | 1.06 |
Cost of Increment Transaction
Parties | Tx size | % max Mem | % max CPU | Min fee ₳ |
---|---|---|---|---|
1 | 1794 | 25.11 | 8.24 | 0.49 |
2 | 1890 | 25.63 | 9.00 | 0.51 |
3 | 2091 | 28.77 | 10.68 | 0.55 |
5 | 2412 | 33.05 | 13.47 | 0.62 |
10 | 3043 | 40.74 | 19.14 | 0.75 |
37 | 7316 | 96.88 | 55.47 | 1.65 |
Cost of Decrement Transaction
Parties | Tx size | % max Mem | % max CPU | Min fee ₳ |
---|---|---|---|---|
1 | 597 | 23.99 | 7.61 | 0.43 |
2 | 825 | 26.74 | 9.04 | 0.47 |
3 | 949 | 28.17 | 10.10 | 0.49 |
5 | 1280 | 32.92 | 12.75 | 0.56 |
10 | 1912 | 41.17 | 18.34 | 0.70 |
41 | 6464 | 98.47 | 54.79 | 1.63 |
Close
transaction costs
Parties | Tx size | % max Mem | % max CPU | Min fee ₳ |
---|---|---|---|---|
1 | 643 | 30.95 | 9.68 | 0.50 |
2 | 791 | 32.89 | 10.94 | 0.53 |
3 | 924 | 34.83 | 12.18 | 0.56 |
5 | 1354 | 40.48 | 15.56 | 0.65 |
10 | 2150 | 48.28 | 21.48 | 0.79 |
34 | 5621 | 96.47 | 52.99 | 1.56 |
Contest
transaction costs
Parties | Tx size | % max Mem | % max CPU | Min fee ₳ |
---|---|---|---|---|
1 | 680 | 35.99 | 11.01 | 0.55 |
2 | 818 | 38.48 | 12.46 | 0.59 |
3 | 975 | 40.32 | 13.65 | 0.62 |
5 | 1359 | 46.73 | 17.19 | 0.71 |
10 | 1980 | 57.27 | 23.61 | 0.87 |
27 | 4720 | 99.49 | 48.53 | 1.51 |
Abort
transaction costs
There is some variation due to the random mixture of initial and already committed outputs.
Parties | Tx size | % max Mem | % max CPU | Min fee ₳ |
---|---|---|---|---|
1 | 5981 | 28.32 | 9.34 | 0.71 |
2 | 6094 | 37.44 | 12.33 | 0.81 |
3 | 6223 | 44.63 | 14.70 | 0.89 |
4 | 6339 | 53.64 | 17.68 | 0.99 |
5 | 6580 | 67.90 | 22.47 | 1.15 |
6 | 6594 | 75.71 | 25.05 | 1.23 |
7 | 6632 | 81.37 | 26.76 | 1.29 |
8 | 6890 | 93.27 | 30.82 | 1.43 |
FanOut
transaction costs
Involves spending head output and burning head tokens. Uses ada-only UTXO for better comparability.
Parties | UTxO | UTxO (bytes) | Tx size | % max Mem | % max CPU | Min fee ₳ |
---|---|---|---|---|---|---|
10 | 0 | 0 | 6092 | 19.66 | 6.46 | 0.62 |
10 | 1 | 57 | 6125 | 20.87 | 6.98 | 0.64 |
10 | 5 | 285 | 6261 | 30.31 | 10.59 | 0.75 |
10 | 10 | 569 | 6430 | 41.61 | 14.95 | 0.88 |
10 | 20 | 1140 | 6772 | 62.00 | 22.90 | 1.11 |
10 | 30 | 1709 | 7112 | 83.57 | 31.25 | 1.36 |
10 | 37 | 2108 | 7350 | 99.40 | 37.34 | 1.55 |
End-to-end benchmark results
This page is intended to collect the latest end-to-end benchmark results produced by Hydra's continuous integration (CI) system from the latest master
code.
Please note that these results are approximate as they are currently produced from limited cloud VMs and not controlled hardware. Rather than focusing on the absolute results, the emphasis should be on relative results, such as how the timings for a scenario evolve as the code changes.
Generated at 2025-04-27 19:16:48.94034884 UTC
Baseline Scenario
Number of nodes | 1 |
---|---|
Number of txs | 300 |
Avg. Confirmation Time (ms) | 4.617904380 |
P99 | 10.87255287ms |
P95 | 5.598792650000001ms |
P50 | 4.359876ms |
Number of Invalid txs | 0 |
Memory data
Time | Used | Free |
---|---|---|
2025-04-27 19:15:32.64811941 UTC | 885M | 6580M |
2025-04-27 19:15:37.648173785 UTC | 1012M | 6348M |
2025-04-27 19:15:42.647978734 UTC | 1014M | 6346M |
2025-04-27 19:15:47.648003908 UTC | 1014M | 6346M |
2025-04-27 19:15:52.647921726 UTC | 1019M | 6340M |
2025-04-27 19:15:57.648052039 UTC | 1019M | 6339M |
Three local nodes
Number of nodes | 3 |
---|---|
Number of txs | 900 |
Avg. Confirmation Time (ms) | 29.884015646 |
P99 | 48.144610369999995ms |
P95 | 41.46351115ms |
P50 | 28.35397ms |
Number of Invalid txs | 0 |
Memory data
Time | Used | Free |
---|---|---|
2025-04-27 19:16:11.601515467 UTC | 934M | 6438M |
2025-04-27 19:16:16.601742814 UTC | 1144M | 6225M |
2025-04-27 19:16:21.602269803 UTC | 1231M | 6068M |
2025-04-27 19:16:26.601715111 UTC | 1227M | 6011M |
2025-04-27 19:16:31.601738686 UTC | 1228M | 6010M |
2025-04-27 19:16:36.601682325 UTC | 1233M | 6004M |
2025-04-27 19:16:41.601686503 UTC | 1235M | 6002M |
2025-04-27 19:16:46.601510814 UTC | 1235M | 6002M |
023bccd
to
21dd19a
Compare
* also added pragma busy_timeout: > to wait up to 5 seconds before returning a 'database is locked' error. both in attempt to solve this error: > SQLite3 returned ErrorBusy while attempting to perform step: database is locked which indicates concurrent write access to db.
* also enhanced rotation log spec
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.
What are you looking to get a review on? As this is a spike .. what is it that you found out and need a review on?
If it is about sqlite: What's the immediate benefit of using sqlite over a plain file? Is it faster or smaller?
If it is about checkpointing: I don't see where the stored events are pruned / result in smaller persistence or faster load time? Also see my comment on #1581 (comment).
@@ -34,6 +34,7 @@ newtype EventSource e m = EventSource | |||
getEvents :: (HasEventId e, MonadUnliftIO m) => EventSource e m -> m [e] | |||
getEvents EventSource{sourceEvents} = runResourceT $ sourceToList sourceEvents | |||
|
|||
-- TODO! putEventBatch |
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.
No, why?
We have at most 2 (or 3) events to persist at any given time.
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.
not required, just a minor suggestion for improvement.
withPersistenceIncremental fp checkpointer action = do | ||
eventLog@PersistenceIncremental{closeDb} <- createRotatedEventLog fp checkpointerHandle | ||
void $ action eventLog | ||
closeDb |
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.
This may never be executed in presence of exceptions -> use bracket
(PersistenceIncremental a IO -> IO b) -> | ||
IO () | ||
withPersistenceIncremental fp checkpointer action = do | ||
eventLog@PersistenceIncremental{closeDb} <- createRotatedEventLog fp checkpointerHandle |
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 checkpointing specific to the sqlite persistence? If not than this should be specified orthogonal to it.
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.
yes, it is a bit specific.
lets do it orthogonal in a separate PR!
atomically getLastSeenEventId >>= \case | ||
Nothing -> store evt | ||
Just lastSeenEventId | ||
| getEventId evt > lastSeenEventId -> store evt |
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.
No need to keep track of a last seen event id here as the sqlite database should make it very easy to not write the same key that is already present (or overwrite it).
createWriteConnectionV fp = do | ||
createDirectoryIfMissing True $ takeDirectory fp | ||
conn <- open fp | ||
execute_ conn "PRAGMA journal_mode = WAL;" |
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 remember when working on this we had problems with performance, hopefully these settings make the sqlitedb faster to read/write.
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 increase in performance comes from using a singleton connection rather than opening a new one for every db action
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.
WAL mode is still good for failure resiliency
As far as I can see, comparing to some other PRs, it seems that this is now almost exactly the same speed as it was before? i.e. no noticable impact? If so, amazing. Can you run some performance tests on this PR and the main branch so we can be certain of the impact? (And post some graphs!) Very cool if so :) |
Closing because :
|
Follow up on: #1746