Skip to content

improve performance of XmlComplexContentImpl.arraySetterHelper#30

Closed
pjfanning wants to merge 1 commit intoapache:trunkfrom
pjfanning:issue-483
Closed

improve performance of XmlComplexContentImpl.arraySetterHelper#30
pjfanning wants to merge 1 commit intoapache:trunkfrom
pjfanning:issue-483

Conversation

@pjfanning
Copy link
Copy Markdown
Member

@pjfanning pjfanning commented Apr 21, 2026

When saving large XLSX files via POI, arraySetterHelper iterates over N source elements and for each calls find_element_user(QName, int i) with a monotonically increasing i. Since find_element_user always rescans from _firstChild, this is O(n) per call — O(n²) total for N elements.

https://issues.apache.org/jira/browse/XMLBEANS-438

Changes

  • commonSetterHelper / commonSetterHelper2: Pre-fetch all existing child elements once with find_all_element_users (O(n)) before the loop, then use O(1) list indexing instead of find_element_user(name, i) on each iteration.

  • arraySetterHelper fast-path inner loop: Replaces the per-iteration find_element_user(name, j) call with existingList.get(j - originalI - insertCount). An insertCount counter tracks in-loop insertions that shift the original elements rightward in the store, keeping the index arithmetic correct without re-scanning.

  • arraySetterHelper general-case final loop: Lazily builds a finalList after the excess-removal pass, then uses finalList.get(j) for existing positions instead of find_element_user(name, j).

Before:

// O(n) scan from _firstChild on every call — O(n²) total
for (int i = 0; i < n; i++) {
    user = store.find_element_user(elemName, i); // rescans from _firstChild each time
    ((XmlObjectBase) user).set(sources[i]);
}

After:

// O(n) once, then O(1) per element
List<XmlObject> existing = new ArrayList<>(m);
store.find_all_element_users(elemName, existing);

for (int i = 0; i < n; i++) {
    XmlObjectBase user = (i >= m) ? (XmlObjectBase) store.add_element_user(elemName)
                                   : (XmlObjectBase) existing.get(i);
    fun.accept(user, i);
}

Overall complexity for N-element array setter operations: O(n²) → O(n).

@pjfanning
Copy link
Copy Markdown
Member Author

JMH testing in https://github.com/pjfanning/poi-bench shows none of the expected performance benefit

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.

1 participant