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
{{ message }}
Repository navigation
DocumentIndexer.containsTuple uses shallow Arrays.equals, so an array-valued key churns remove+re-put on every update (the #5318 defect in the new #6934 path) #7109
The #6934 fix introduced a tuple-level delta for composite indexes with one collection modifier. Its containsTuple helper compares tuples with the shallow Arrays.equals, so a tuple element that is itself an array never matches - which is exactly the defect #5318 fixed for the scalar-only branch of the same method, with a comment naming the same example.
Not a correctness bug: the final index state is right. It is a spurious remove + re-put on every update of such a record.
Where (HEAD 38034d9c8)
engine/src/main/java/com/arcadedb/database/DocumentIndexer.java:537-542, added by the #6934 fix:
privatestaticbooleancontainsTuple(finalList<Object[]> tuples, finalObject[] tuple) {
for (finalObject[] t : tuples)
if (Arrays.equals(t, tuple))
returntrue;
returnfalse;
}
Arrays.equals on two Object[] compares elements with Object.equals(). For an element that is itself an array that is identity, so two independently deserialized but identical arrays compare unequal.
The precedent is in the same file, :648-653, where #5318 established the opposite for the scalar-only path - and the comment names the very case:
// Use content-aware comparison: array-typed keys (e.g. the float[] of a vector index) do not override// Object.equals(), so two independently deserialized-but-identical arrays would compare unequal and// trigger a spurious remove()+put() on every record update (issue #5318). Objects.deepEquals falls back// to Object.equals() for scalar keys and to element-wise Arrays.equals() for array keys.if (!keyValuesAreModified && !Objects.deepEquals(newKeyValues[i], oldKeyValues[i]))
Impact
A composite index over an array-valued scalar plus a BY ITEM property - the shape the #6934 fix created this path for - churns index.remove(oldTuple, rid) followed by index.put(newTuple, rid) on every update of the record, even when neither key changed. That is index write amplification and extra WAL per update, on the path a user reaches by declaring exactly the kind of index #6934 made work.
Correctness is unaffected: remove-then-put lands on the same final state, and the removes precede the puts (:523-533), so no live entry is lost.
Suggested fix
Arrays.deepEquals(t, tuple) at :539. One word, and it makes the composite path agree with the scalar path that #5318 already settled.
Worth noting for whoever takes it: the two branches now use two different comparison policies for the same question, which is the drift that produced this. A shared helper would prevent the third path from picking a third policy.
Scope / confidence
High on the mechanism and the precedent - both quoted above from the same file. Filed as low severity because the outcome is redundant writes rather than a wrong answer.
Updating a record indexed by a composite index that mixes a BY ITEM/BY KEY/BY VALUE property with an array-valued key (a BINARY property, for example) no longer removes and re-adds its index entries when the indexed values did not change. Every key comparison in the indexer now goes through one content-aware equality, so the same slip cannot come back through another update path.
❤️ Thanks for helping make ArcadeDB better! ArcadeDB is free and open source, sustained by its community. If it's useful to you or your company, please consider becoming a sponsor to keep development going.
Activity
fix(#7109,#7111): route the FULL_TEXT BY ITEM update through the shar…
Merge pull request #7117 from ArcadeData/fix/issues-7109-7110-7111-7112
lvca commentedon Sep 3, 2026
Fixed in #7117 (milestone 26.9.1).
Updating a record indexed by a composite index that mixes a
BY ITEM/BY KEY/BY VALUEproperty with an array-valued key (aBINARYproperty, for example) no longer removes and re-adds its index entries when the indexed values did not change. Every key comparison in the indexer now goes through one content-aware equality, so the same slip cannot come back through another update path.❤️ Thanks for helping make ArcadeDB better! ArcadeDB is free and open source, sustained by its community. If it's useful to you or your company, please consider becoming a sponsor to keep development going.
fix(ArcadeData#7109,ArcadeData#7110,ArcadeData#7111,ArcadeData#7112):…
fix(engine): the transaction index overlay compares array-valued keys…