You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The `matchResourceMetadataStrict` utility (`utils.js`) determines if a resource is "unchanged" using a tiered comparison (cheapest first):
221
+
The `isResourceUnchanged` utility (`utils.js`) determines if a resource is "unchanged" using a tiered comparison (cheapest first):
222
222
223
-
1. If `lastModified` matches cached value AND differs from `indexTimestamp`: unchanged (fast path)
224
-
2. If `lastModified` equals `indexTimestamp`: racy-git edge case -- file may have changed during indexing, fall through to integrity check
225
-
3. Compare `size` -- if different, changed
226
-
4. Compare `integrity` hash -- expensive, last resort
223
+
1. Compare `size` -- if different, changed (definite signal; mtime preservation via `cp -p`/`tar -x`/atomic rename does not imply unchanged content)
224
+
2. Compare `inode` -- if different, the file was replaced; fall through to integrity check rather than rejecting outright (content may still be identical)
225
+
3. If `lastModified` matches cached value AND differs from `indexTimestamp` AND inode matches: unchanged (fast path)
226
+
4. If `lastModified` equals `indexTimestamp`: racy-git edge case -- file may have changed during indexing, fall through to integrity check
227
+
5. Compare `integrity` hash -- expensive, last resort
227
228
228
-
Note: inode comparison is defined but currently commented out. `inode` is still stored in TreeNode for future use.
229
+
`inode`is optional on both sides (virtual resources, older caches without inode); the inode check is skipped when either side is undefined.
perf #flushTreeChanges for task 'replaceVersion' completed in 16.79 ms across 1 registries
155
155
perf Updated project indices for task replaceVersion in project sap.m in 21.71 ms
156
156
```
@@ -160,7 +160,7 @@ Key metrics:
160
160
-**phase1(removals)**: Time removing deleted resources from the Merkle tree.
161
161
-**phase2(upserts)**: Time inserting/updating resources in the tree.
162
162
-**phase3(rehash)**: Time propagating hash changes up from modified leaves to root. High rehash with few changed resources indicates deep tree structure.
163
-
-**matchMetadataStrictCalls / matchMetadataUnchanged**: How many resources were compared, and how many were unchanged (short-circuited by lastModified check). If `calls >> unchanged`, many resources needed content hashing.
163
+
-**isUnchangedCalls / isUnchangedHits**: How many resources were compared, and how many were unchanged (short-circuited by lastModified check). If `calls >> hits`, many resources needed content hashing.
164
164
165
165
Then task execution or skip:
166
166
@@ -217,14 +217,15 @@ The four sub-operations (stages, requests, sourceIndex, result) run in parallel
217
217
218
218
## UI5_CACHE_PERF Counters
219
219
220
-
Setting `UI5_CACHE_PERF=1` enables low-level counters in `utils.js` for `matchResourceMetadataStrict`:
220
+
Setting `UI5_CACHE_PERF=1` enables low-level counters in `utils.js` for `isResourceUnchanged`:
221
221
222
222
-`calls` — Total invocations
223
223
-`shortCircuitTrue` — Fast-path returns (lastModified matches cached and ≠ indexTimestamp → file unchanged, no I/O needed)
224
224
-`sizeMismatch` — Changes detected via size check (cheap)
-`integrityFallback` — Full SHA256 content hash required (expensive)
226
227
227
-
These counters appear in the `TreeRegistry.flush`log as `matchMetadataStrictCalls` and `matchMetadataUnchanged`.
228
+
These counters are tallied per-flush in `TreeRegistry.flush` as `isUnchangedCalls` and `isUnchangedHits`.
228
229
229
230
A high `integrityFallback` count means many files have the same size but different content — this is expensive and may indicate that the `lastModified` short-circuit is not working (e.g., due to timestamp resolution issues).
230
231
@@ -303,13 +304,13 @@ These four operations run in parallel. They share I/O bandwidth, so their indivi
303
304
304
305
**Note:** In CLI mode, cache writes are deferred to the background. The `Wrote build cache` log line appears after `Build succeeded`. The sub-timings tend to be lower (~250-300ms vs ~1400ms) because background writes don't compete with the build for I/O bandwidth.
305
306
306
-
### 5. matchMetadataUnchanged vs modifiedNodesSkips
307
+
### 5. isUnchangedHits vs modifiedNodesSkips
307
308
308
309
In `TreeRegistry.flush` logs:
309
-
-`matchMetadataUnchanged` — Resources whose metadata (lastModified, size, integrity) matched the cached version. No tree modification needed.
310
+
-`isUnchangedHits` — Resources whose metadata (lastModified, size, integrity) matched the cached version. No tree modification needed.
310
311
-`modifiedNodesSkips` — Tree nodes already marked as modified by a previous flush in the same build. Skipped to avoid redundant work.
311
312
312
-
When `matchMetadataUnchanged` equals `matchMetadataStrictCalls`, ALL resources were unchanged — the flush was pure overhead.
313
+
When `isUnchangedHits` equals `isUnchangedCalls`, ALL resources were unchanged — the flush was pure overhead.
313
314
314
315
### 6. Dependency index "changed=true" doesn't always mean task re-execution
315
316
@@ -367,7 +368,7 @@ When diagnosing slow `writeStageResources`, check the `CAS skipped` vs `CAS writ
367
368
4.**Drill down.** For the dominant phase:
368
369
- Add more granular `log.perf()` statements if needed
369
370
- Use `console.time()`/`console.timeEnd()` for quick local profiling
370
-
- Check `matchMetadataStrictCalls` vs `matchMetadataUnchanged` to understand if resources are being unnecessarily re-hashed
371
+
- Check `isUnchangedCalls` vs `isUnchangedHits` to understand if resources are being unnecessarily re-hashed
371
372
372
373
5.**Validate optimization ideas.** When proposing optimizations:
373
374
- Consider warm vs stale vs cold cache impact separately
0 commit comments