maedhroz commented on PR #4900:
URL: https://github.com/apache/cassandra/pull/4900#issuecomment-4791782382

   Pasting the bits surfaced from a quick CC skill-assisted review here, and 
then I'll do a more careful manual review:
   
   ```
    Finding 1: if (allocated > 0) silently swallows net releases — contradicts 
patch's stated net-delta semantics
   
     - Location: src/java/org/apache/cassandra/utils/btree/BTree.java:3713-3714
     - Confidence: High (latent active bug; certain consistency hazard)
     - Flagged by: Logic, Boundary, Resources, Completeness, Symmetry (5 
specialists)
     - What's wrong: After the patch, Updater.allocated is documented and used 
as a true net delta (addAllocated adds for newly retained nodes, subtracts for 
replaced sources, root release included). But the report site still gates on 
allocated > 0, dropping any zero or negative result. This collides on two axes: 
(a) the sentinel -1
     overloads "tracking disabled" with "net release" — once allocated goes 
below zero it stays negative and future addAllocated calls become no-ops 
because the helper guards on allocated >= 0; (b) the parallel report sites at 
BTree.java:382, 397 are unconditional/signed, so this is the only asymmetric 
guard.
     - Why current code doesn't trigger it: BTree.update's reconciler is 1-to-1 
(no key removal), so per-step addAllocated arguments are non-negative across 
all paths the symmetry/logic agents traced (drain, redistributeAndDrain, 
redistributeOverflowAndDrain, propagateOverflow). The patch's 
BTreeUpdateHeapAccountingTest does not
     exercise a net-zero-or-negative outcome — the closest case (root reuse on 
identical-shape merge) is not in the scenario set.
     - Suggested fix: replace the report condition with if (allocated != 0) and 
decouple "tracking disabled" from the value of allocated (e.g. a boolean 
accountingEnabled set once at the start of update). Add a scenario to 
BTreeUpdateHeapAccountingTest where every key in insert already exists with 
identical content (root reuse →
     allocated == 0).
   
     Finding 2: UpdateFunction.onAllocatedOnHeap javadoc still describes the 
old semantics
   
     - Location: 
src/java/org/apache/cassandra/utils/btree/UpdateFunction.java:46-49
     - Confidence: High
     - Flagged by: Completeness
     - What's wrong: Javadoc reads @param heapSize extra heap space allocated 
(over previous tree). After this patch the parameter is a signed net delta — 
the new BTreeRow.merge and ColumnData.removeShadowed call sites can pass 
negative values today. Future implementers reading the contract may add a 
non-negative assert and silently
     break accounting.
     - Suggested fix: state explicitly that the value is a signed delta and may 
be negative when more heap is released than allocated.
   
     Finding 3: AbstractFastBuilder.reset() does not clear the leaf-level 
sourceNode; the new root setSourceNode(update) widens the leak window
   
     - Location: src/java/org/apache/cassandra/utils/btree/BTree.java:3511-3532 
(reset) and :3706 (the new root assignment)
     - Confidence: Medium
     - Flagged by: Concurrency, Symmetry
     - What's wrong: reset() walks branch = leaf().parent clearing each 
parent's sourceNode, but never clears the leaf builder's own sourceNode. 
Pre-patch this was an idle latent issue because LeafBuilder.drain() always 
cleared it on the success path. Post-patch, Updater.update() now eagerly sets 
builder.setSourceNode(update) before
     updateRecursive runs — so any exception thrown between line 3706 and the 
next drain() returns the Updater to the FastThreadLocal pool with a dangling 
reference to the previous update tree's root array. The dangling ref is 
eventually overwritten on the next update() reaching the leaf level, but until 
then the pooled Updater
     pins memory.
     - Suggested fix: add clearSourceNode() (the leaf-level call on this) at 
the top or bottom of AbstractFastBuilder.reset().
   
     Finding 4: LeafBuilder.propagateOverflow not migrated to 
addAllocated(shallowHeapOf(savedBuffer))
   
     - Location: src/java/org/apache/cassandra/utils/btree/BTree.java:2896-2905
     - Confidence: Medium (consistency, not correctness today)
     - Flagged by: Boundary, Concurrency, Resources, Symmetry (4 specialists)
     - What's wrong: Every other allocation/release point in 
LeafBuilder/BranchBuilder was rewritten through addAllocated(...) plus 
shallowHeapOf(...)/sizeOnHeapOfLeaf(...); this one site still uses the 
inline-guarded allocated += ObjectSizes.sizeOfReferenceArray(MAX_KEYS). 
Numerically equivalent today (savedBuffer is new
     Object[MAX_KEYS]), but the inconsistency is exactly the kind of asymmetric 
edit that produced four of the five bugs the patch is fixing.
     - Suggested fix: replace with 
leaf.addAllocated(shallowHeapOf(savedBuffer));.
   
     Finding 5: recordDeletion.onAllocatedOnHeap(...) in removeShadowed is 
computed and discarded on the noOp path
   
     - Location: src/java/org/apache/cassandra/db/rows/ColumnData.java:230-232 
(with noOp defined at :67-89)
     - Confidence: Low (efficiency, not correctness)
     - Flagged by: Completeness
     - What's wrong: When recordDeletion == ColumnData.noOp (the update side / 
Reconciler.merge path), the new line still computes EMPTY_SIZE + 
sizeOnHeapOf(existingTree) and EMPTY_SIZE + sizeOnHeapOf(cells) (each 
potentially walking a multi-node tree) only to pass the result to a no-op. 
Trivial fix: gate on recordDeletion != noOp.
   
     Finding 6: removeShadowed does not subtract complexDeletion.dataSize() 
when a complex column is dropped
   
     - Location: src/java/org/apache/cassandra/db/rows/ColumnData.java:200-233
     - Confidence: Low (out of patch scope; small dataSize drift, not heap)
     - Flagged by: Resources
     - What's wrong: BTreePartitionUpdater.insert(ColumnData) originally added 
insert.dataSize() (which for ComplexColumnData includes 
complexDeletion.dataSize() == 12). The patch's release path subtracts each 
cell's dataSize via recordDeletion.delete and the wrapper+tree heap via 
onAllocatedOnHeap, but never subtracts the
     complexDeletion.dataSize(). Heap accounting (the patch's stated target) is 
fine; dataSize accumulates 12 stranded bytes per dropped complex column with a 
non-LIVE complexDeletion. Adjacent to the patch, would be a one-line fix.
   
     Finding 7: Latent paths that don't release sourceNode if reached
   
     - Location: LeafBuilder.drain() count==0 early return at 
BTree.java:2951-2956; BranchBuilder.drain() count==0 / right-child collapse at 
:3261-3270
     - Confidence: Low (currently unreachable from the patched call paths)
     - Flagged by: Resources, Symmetry
     - What's wrong: Both early-return branches clearSourceNode() without first 
releasing the source's shallow heap through addAllocated. BTree.update's 
reconciler doesn't drop keys, so neither branch is reachable from the Updater 
today. Worth either an assertion or a defensive 
addAllocated(-shallowHeapOf(sourceNode)) so the new
     "every replaced source releases its shallow heap" invariant holds globally.
   ```


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to