Conversation
|
When no metrics implementation was given New() used an unpublished
ExpVarMetrics. As it's not published and not otherwise accessible,
nothing could observe these metrics, yet every write transaction paid
for building the metric keys and allocating the expvar values. This
also applied when using the hive Cell without providing Metrics.
Default to NopMetrics instead.
│ old │ new │
│ sec/op │ sec/op vs base │
DB_WriteTxn_1_DefaultMetrics 1149.5n ± 4% 761.2n ± 6% -33.78% (p=0.002 n=6)
│ B/op │ B/op vs base │
DB_WriteTxn_1_DefaultMetrics 896.0 ± 0% 656.0 ± 0% -26.79% (p=0.002 n=6)
│ allocs/op │ allocs/op vs base │
DB_WriteTxn_1_DefaultMetrics 25.00 ± 0% 13.00 ± 0% -48.00% (p=0.002 n=6)
AIL:3
Signed-off-by: Jussi Maki <jussi@isovalent.com>
The gauge metrics of ExpVarMetrics allocated a new expvar.Int and
replaced the map entry on every update. The object count, graveyard
object count and revision gauges are updated for each modified table on
every commit. Update the existing value in place if it exists.
│ old │ new │
│ sec/op │ sec/op vs base │
DB_WriteTxn_1_ExpVarMetrics 1153.0n ± 1% 960.3n ± 0% -16.71% (p=0.002 n=6)
│ old │ new │
│ B/op │ B/op vs base │
DB_WriteTxn_1_ExpVarMetrics 896.0 ± 0% 680.0 ± 0% -24.11% (p=0.002 n=6)
│ old │ new │
│ allocs/op │ allocs/op vs base │
DB_WriteTxn_1_ExpVarMetrics 25.00 ± 0% 16.00 ± 0% -36.00% (p=0.002 n=6)
AIL:3
Signed-off-by: Jussi Maki <jussi@isovalent.com>
Commit() stored a pointer to a local slice header as the new root,
which forced a heap allocation on every commit. The write transaction
handle already holds a readTxn for the ReadTxn returned from Commit(),
so store the root there and publish a pointer to it instead.
│ old │ new │
│ sec/op │ sec/op vs base │
DB_WriteTxn_1 778.5n ± 1% 758.5n ± 2% -2.58% (p=0.002 n=6)
DB_WriteTxn_CommitOnly_1Table 436.2n ± 2% 414.9n ± 1% -4.89% (p=0.002 n=6)
geomean 582.8n 561.0n -3.74%
│ old │ new │
│ objects/sec │ objects/sec vs base │
DB_WriteTxn_1 1.284M ± 1% 1.318M ± 2% +2.65% (p=0.002 n=6)
│ old │ new │
│ B/op │ B/op vs base │
DB_WriteTxn_1 656.0 ± 0% 632.0 ± 0% -3.66% (p=0.002 n=6)
DB_WriteTxn_CommitOnly_1Table 224.0 ± 0% 200.0 ± 0% -10.71% (p=0.002 n=6)
geomean 383.3 355.5 -7.25%
│ old │ new │
│ allocs/op │ allocs/op vs base │
DB_WriteTxn_1 13.00 ± 0% 12.00 ± 0% -7.69% (p=0.002 n=6)
DB_WriteTxn_CommitOnly_1Table 4.000 ± 0% 3.000 ± 0% -25.00% (p=0.002 n=6)
geomean 7.211 6.000 -16.79%
AIL:3
Signed-off-by: Jussi Maki <jussi@isovalent.com>
Commit() iterated over all tables in the database twice, once to commit
the indexes of the locked tables and once to refresh the unlocked table
entries from the current root, and Abort() once to find the locked
tables. With many tables this dominated the cost of small write
transactions.
Keep track of the locked table entries in the transaction and iterate
over them instead. Refresh the unlocked entries only if the root has
changed since the transaction was created by copying the current root
and putting the locked entries back into it.
│ old │ new │
│ sec/op │ sec/op vs base │
DB_WriteTxn_CommitOnly_100Tables 695.2n ± 1% 542.7n ± 1% -21.94% (p=0.000 n=8)
DB_WriteTxn_CommitOnly_1Table 399.1n ± 1% 396.8n ± 0% ~ (p=0.069 n=8)
DB_WriteTxnCommit100 686.3n ± 1% 535.7n ± 1% -21.95% (p=0.000 n=8)
geomean 575.3n 486.8n -15.39%
AIL:3
Signed-off-by: Jussi Maki <jussi@isovalent.com>
A single table write transaction called time.Now() six times: twice
around locking the tables, twice when locking each table, once per
table when releasing it and once for the transaction duration.
Have SortableMutexes.Lock() return the start and acquire times and
derive the per-mutex acquire durations from consecutive timestamps. On
commit and abort take a single timestamp for releasing the tables and
for the transaction duration metric.
│ old │ new │
│ sec/op │ sec/op vs base │
DB_WriteTxn_1 742.0n ± 20% 703.9n ± 11% -5.14% (p=0.023 n=10)
DB_WriteTxn_CommitOnly_1Table 431.9n ± 8% 369.6n ± 8% -14.44% (p=0.002 n=10)
DB_NewWriteTxn 384.4n ± 11% 338.9n ± 35% ~ (p=0.075 n=10)
geomean 497.6n 445.1n -10.55%
AIL:3
Signed-off-by: Jussi Maki <jussi@isovalent.com>
modify() and delete() already look up the table entry and check that it
is locked, but then used mustIndexWriteTxn() for each index which looked
up the table entry again through the TableMeta interface and re-checked
the lock. Get the index transactions directly from the table entry.
│ old │ new │
│ sec/op │ sec/op vs base │
DB_WriteTxn_100 294.7n ± 4% 287.2n ± 3% ~ (p=0.148 n=10)
DB_WriteTxn_100_SecondaryIndex 470.0n ± 2% 457.8n ± 2% -2.60% (p=0.004 n=10)
DB_Modify 350.2µ ± 5% 341.4µ ± 6% ~ (p=0.218 n=10)
DB_RandomReplace 601.3µ ± 5% 602.7µ ± 5% ~ (p=0.529 n=10)
geomean 13.07µ 12.82µ -1.86%
AIL:3
Signed-off-by: Jussi Maki <jussi@isovalent.com>
joamaki
force-pushed
the
pr/joamaki/minor-writetxn-optimizations
branch
from
September 30, 2026 07:15
df64b71 to
c7554ca
Compare
joamaki
marked this pull request as ready for review
September 30, 2026 07:17
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
statedb.Newnow defaults toNopMetricsinstead ofExpVarMetricsexpvar.Intallocation inExpVarMetricstime.Nowin write transactions (WriteTxn_1 742ns/op -> 703ns/op (-5%))Benchstat highlights:
AIL:3