[Tree widget]: add abstract batching cache on next#1681
Merged
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
Extracts the timer-based batching, deduplication, and caching logic from DescendantsCountCache into a new abstract BatchingCache base class so the same machinery can later be reused by ChildElementsCache (to be done in a follow-up PR). DescendantsCountCache is refactored to extend the new base class, exposing its specifics (batch shape, query building, row insertion) via protected hooks.
Changes:
- Add new
BatchingCache<TRequest, TBatch, TResult, TItem, TRow>abstract class that owns the 20ms batch timer, in-flight deduplication, buffer-and-query pipeline, and result/caching plumbing (configurable buffer size, timer delay, release-on-count). - Refactor
DescendantsCountCacheto extendBatchingCache, implementinggetCachedValue/getGuaranteedCachedValue/getValuesToRequest/createBatch/addRequestToBatch/getIterable/executeQuery/insertRow/ensureDefaultCacheEntries, and exposinggetDescendantsCountsas a thin wrapper overget. - Introduce supporting
DescendantsCountRequest,DescendantsCountResult,Batch,WhereClause, andRowtypes inDescendantsCountCache.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| packages/itwin/tree-widget/src/tree-widget-react/components/trees/common/internal/caches/BatchingCache.ts | New abstract base class encapsulating batching, deduplication, and caching shared between caches. |
| packages/itwin/tree-widget/src/tree-widget-react/components/trees/common/internal/caches/DescendantsCountCache.ts | Refactored to extend BatchingCache, with previously-inline batching/query logic moved into protected hooks. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Tree-Widget Next benchmark
| Benchmark suite | Current: c8a3ab5 | Previous: 45b95b4 | Deviation | Status |
|---|---|---|---|---|
models tree 50k 3D elements search > get search paths |
1218 ms |
1274 ms |
-4.40% |
〰️ |
models tree 50k 3D elements search > get search paths (P95 of main thread blocks) |
54 ms |
53 ms |
1.89% |
〰️ |
models tree 50k 3D elements search > load hierarchy from search paths |
113223 ms |
114168 ms |
-0.83% |
〰️ |
models tree 50k 3D elements search > load hierarchy from search paths (P95 of main thread blocks) |
41 ms |
40 ms |
2.50% |
〰️ |
models tree 50k categories > collect nodes |
2814 ms |
3000 ms |
-6.20% |
〰️ |
models tree 50k categories > collect nodes (P95 of main thread blocks) |
127 ms |
106 ms |
19.81% |
〰️ |
models tree 50k categories > validate initial visibility |
2569 ms |
2588 ms |
-0.73% |
〰️ |
models tree 50k categories > validate initial visibility (P95 of main thread blocks) |
0 ms |
0 ms |
0% |
🟰 |
models tree 50k categories > change visibility |
71 ms |
75 ms |
-5.33% |
〰️ |
models tree 50k categories > change visibility (P95 of main thread blocks) |
60 ms |
64 ms |
-6.25% |
〰️ |
models tree 50k categories > validate changed visibility |
4794 ms |
4691 ms |
2.20% |
〰️ |
models tree 50k categories > validate changed visibility (P95 of main thread blocks) |
31 ms |
26 ms |
19.23% |
〰️ |
models tree 50k 3D elements > collect nodes |
45542 ms |
45626 ms |
-0.18% |
〰️ |
models tree 50k 3D elements > collect nodes (P95 of main thread blocks) |
71 ms |
67 ms |
5.97% |
〰️ |
models tree 50k 3D elements > validate initial visibility |
2489 ms |
2549 ms |
-2.35% |
〰️ |
models tree 50k 3D elements > validate initial visibility (P95 of main thread blocks) |
0 ms |
0 ms |
0% |
🟰 |
models tree 50k 3D elements > change model visibility |
19 ms |
21 ms |
-9.52% |
〰️ |
models tree 50k 3D elements > change model visibility (P95 of main thread blocks) |
0 ms |
0 ms |
0% |
🟰 |
models tree 50k 3D elements > validate changed model visibility |
2585 ms |
2564 ms |
0.82% |
〰️ |
models tree 50k 3D elements > validate changed model visibility (P95 of main thread blocks) |
24 ms |
0 ms |
2400% |
〰️ |
models tree 50k 3D elements > change category node visibility |
527 ms |
503 ms |
4.77% |
〰️ |
models tree 50k 3D elements > change category node visibility (P95 of main thread blocks) |
59 ms |
52 ms |
13.46% |
〰️ |
models tree 50k 3D elements > validate changed category visibility |
2515 ms |
2575 ms |
-2.33% |
〰️ |
models tree 50k 3D elements > validate changed category visibility (P95 of main thread blocks) |
0 ms |
0 ms |
0% |
🟰 |
models tree 50k 3D elements > validate per-model category override |
2518 ms |
2501 ms |
0.68% |
〰️ |
models tree 50k 3D elements > validate per-model category override (P95 of main thread blocks) |
0 ms |
0 ms |
0% |
🟰 |
models tree 50k 3D elements > change element visibility |
9 ms |
10 ms |
-10% |
〰️ |
models tree 50k 3D elements > change element visibility (P95 of main thread blocks) |
0 ms |
0 ms |
0% |
🟰 |
models tree 50k 3D elements > validate changed element visibility |
3211 ms |
3269 ms |
-1.77% |
〰️ |
models tree 50k 3D elements > validate changed element visibility (P95 of main thread blocks) |
83 ms |
71 ms |
16.90% |
〰️ |
models tree 50k 3D child elements with different categories > collect nodes |
45175 ms |
46013 ms |
-1.82% |
〰️ |
models tree 50k 3D child elements with different categories > collect nodes (P95 of main thread blocks) |
55 ms |
64 ms |
-14.06% |
〰️ |
models tree 50k 3D child elements with different categories > validate initial visibility |
2479 ms |
2478 ms |
0.04% |
〰️ |
models tree 50k 3D child elements with different categories > validate initial visibility (P95 of main thread blocks) |
0 ms |
0 ms |
0% |
🟰 |
models tree 50k 3D child elements with different categories > change visibility |
11 ms |
10 ms |
10% |
〰️ |
models tree 50k 3D child elements with different categories > change visibility (P95 of main thread blocks) |
0 ms |
0 ms |
0% |
🟰 |
models tree 50k 3D child elements with different categories > validate changed visibility |
3096 ms |
3264 ms |
-5.15% |
〰️ |
models tree 50k 3D child elements with different categories > validate changed visibility (P95 of main thread blocks) |
67 ms |
81 ms |
-17.28% |
〰️ |
categories tree 50k subCategories search > get search paths |
1887 ms |
1924 ms |
-1.92% |
〰️ |
categories tree 50k subCategories search > get search paths (P95 of main thread blocks) |
44 ms |
45 ms |
-2.22% |
〰️ |
categories tree 50k subCategories search > load hierarchy from search paths |
5432 ms |
5581 ms |
-2.67% |
〰️ |
categories tree 50k subCategories search > load hierarchy from search paths (P95 of main thread blocks) |
47 ms |
51 ms |
-7.84% |
〰️ |
categories tree 50k subCategories > collect nodes |
6060 ms |
6044 ms |
0.26% |
〰️ |
categories tree 50k subCategories > collect nodes (P95 of main thread blocks) |
48 ms |
49 ms |
-2.04% |
〰️ |
categories tree 50k subCategories > validate initial visibility |
1684 ms |
1703 ms |
-1.12% |
〰️ |
categories tree 50k subCategories > validate initial visibility (P95 of main thread blocks) |
21 ms |
22 ms |
-4.55% |
〰️ |
categories tree 50k subCategories > change visibility |
344 ms |
348 ms |
-1.15% |
〰️ |
categories tree 50k subCategories > change visibility (P95 of main thread blocks) |
21 ms |
0 ms |
2100% |
〰️ |
categories tree 50k subCategories > validate changed visibility |
1639 ms |
1620 ms |
1.17% |
〰️ |
categories tree 50k subCategories > validate changed visibility (P95 of main thread blocks) |
36 ms |
31 ms |
16.13% |
〰️ |
categories tree 50k categories > collect nodes |
2455 ms |
2535 ms |
-3.16% |
〰️ |
categories tree 50k categories > collect nodes (P95 of main thread blocks) |
124 ms |
135 ms |
-8.15% |
〰️ |
categories tree 50k categories > validate initial visibility |
7480 ms |
7428 ms |
0.70% |
〰️ |
categories tree 50k categories > validate initial visibility (P95 of main thread blocks) |
92 ms |
70 ms |
31.43% |
〰️ |
categories tree 50k categories > change visibility |
704 ms |
706 ms |
-0.28% |
〰️ |
categories tree 50k categories > change visibility (P95 of main thread blocks) |
49 ms |
53 ms |
-7.55% |
〰️ |
categories tree 50k categories > validate changed visibility |
7509 ms |
7403 ms |
1.43% |
〰️ |
categories tree 50k categories > validate changed visibility (P95 of main thread blocks) |
41 ms |
41 ms |
0% |
🟰 |
classifications tree 50k classifications search > get search paths |
2117 ms |
2223 ms |
-4.77% |
〰️ |
classifications tree 50k classifications search > get search paths (P95 of main thread blocks) |
138 ms |
131 ms |
5.34% |
〰️ |
classifications tree 50k classifications search > load hierarchy from search paths |
69987 ms |
69563 ms |
0.61% |
〰️ |
classifications tree 50k classifications search > load hierarchy from search paths (P95 of main thread blocks) |
26 ms |
21 ms |
23.81% |
〰️ |
classifications tree 50k classifications > collect nodes |
40746 ms |
37771 ms |
7.88% |
〰️ |
classifications tree 50k classifications > collect nodes (P95 of main thread blocks) |
89 ms |
102 ms |
-12.75% |
〰️ |
classifications tree 50k classifications > validate initial visibility |
5104 ms |
4962 ms |
2.86% |
〰️ |
classifications tree 50k classifications > validate initial visibility (P95 of main thread blocks) |
97 ms |
63 ms |
53.97% |
〰️ |
classifications tree 50k classifications > change visibility |
44 ms |
31 ms |
41.94% |
〰️ |
classifications tree 50k classifications > change visibility (P95 of main thread blocks) |
22 ms |
0 ms |
2200% |
〰️ |
classifications tree 50k classifications > validate changed visibility |
5137 ms |
5118 ms |
0.37% |
〰️ |
classifications tree 50k classifications > validate changed visibility (P95 of main thread blocks) |
68 ms |
71 ms |
-4.23% |
〰️ |
This comment was automatically generated by workflow using github-action-benchmark.
saskliutas
reviewed
May 18, 2026
grigasp
reviewed
May 18, 2026
grigasp
approved these changes
May 18, 2026
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.
When reviewing #1678,
Realized I hadn't included the
ChildElementsCacherewrite in the original phases. Thinking we could insert it between phase 1 and phase 2.While trying to implement
ChildElementsCache, considered unifying how it works withDescendantCountsCache. CurrentlyChildElementsCacheexecutes a query per request, whileDescendantCountsCachebatches requests over a 20ms window. The original plan was to keep the structure as-is, but decided that it's better to batchChildElementsCacheas well.This PR includes:
BatchingCacheclass which is used byDescendantCountsCache.DescendantCountsCachechanges to useBatchingCache.Afterwards will create a separate PR for adjusting
ChildElementsCache.