Skip to content

Fix AIndex.entrySet() losing sorted key order via HashSet#652

Merged
brittleboye merged 1 commit into
Convex-Dev:developfrom
anutechrepo77:fix/aindex-entryset-order
Jul 24, 2026
Merged

Fix AIndex.entrySet() losing sorted key order via HashSet#652
brittleboye merged 1 commit into
Convex-Dev:developfrom
anutechrepo77:fix/aindex-entryset-order

Conversation

@anutechrepo77

Copy link
Copy Markdown
Contributor

Fixes #651.

Problem

AIndex documents itself as "a sorted radix-tree map of Blobs to Values" whose primary benefit is to "provide sorted orderings for indexes." That guarantee holds for entryAt(i), but not for entrySet():

@Override
public Set<Entry<K, V>> entrySet() {
    HashSet<Entry<K,V>> hs=new HashSet<>(size());
    long n=count();
    for (long i=0; i<n; i++) {
        MapEntry<K,V> me=entryAt(i);
        hs.add(me);
    }
    return Collections.unmodifiableSet(hs);
}

entryAt(i) walks the radix tree correctly in ascending key order, but the entries are collected into a java.util.HashSet, whose iteration order is hash-bucket-based, not insertion order. Any caller iterating entrySet() directly (or keySet(), forEach, an enhanced-for loop) — a reasonable thing to do given the class's documented sort guarantee — gets entries back in effectively arbitrary order instead.

Fix

Swap HashSet for LinkedHashSet. Since entryAt(i) already inserts in correct ascending order for i = 0..n-1, a LinkedHashSet (which preserves insertion order) is sufficient to restore the documented guarantee — no other logic changes.

Testing

Added IndexTest.testEntrySetOrder(), which builds a 50-entry Index and asserts entrySet()'s iteration order matches entryAt(i) for every i.

  • Fails on the old HashSet implementation (confirmed locally: entry 0 expected, entry 49 observed at the same position)
  • Passes with the LinkedHashSet fix
  • Full convex-core suite: 2812 tests, 0 failures, 0 errors

🤖 Generated with Claude Code

AIndex documents itself as a sorted radix-tree map that provides
sorted orderings for indexes, and entryAt(i) correctly walks the tree
in ascending key order. But entrySet() collected those entries into a
plain HashSet, whose iteration order is hash-bucket-based rather than
insertion order — silently discarding the sort guarantee for any
caller iterating entrySet() (or keySet(), forEach, etc.) directly
instead of calling entryAt(i) in a loop.

Swap HashSet for LinkedHashSet, which preserves the insertion order
entryAt(i) already produces. Adds a regression test that fails on the
old HashSet-based implementation and passes with LinkedHashSet.

Fixes Convex-Dev#651.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

AIndex.entrySet() returns entries in HashSet (unordered) order, not sorted key order

2 participants