Skip to content

Stop the partnerships file gaining blank lines on every save - #610

Merged
uhurusurfa merged 1 commit into
OpenAS2:masterfrom
JakeHuneau:fix/partnerships-blank-line-growth
Sep 16, 2026
Merged

uhurusurfa merged 1 commit into
OpenAS2:masterfrom
JakeHuneau:fix/partnerships-blank-line-growth

Conversation

@JakeHuneau

Copy link
Copy Markdown
Contributor

Storing the partnerships file adds a fresh layer of whitespace to it each time, without bound.

Cause

Two halves that each look fine alone.

loadPartnershipsFile keeps the newlines and indentation between elements as text nodes:

DocumentBuilder parser = factory.newDocumentBuilder();
Document document = parser.parse(inputStream);   // whitespace text nodes retained

storePartnership then asks the serializer to add indentation of its own:

transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");

The serializer cannot remove nodes that are already in the document, so it writes the original whitespace plus a new layer. The next load turns that into more text nodes, and it compounds.

Measured against the shipped partnerships.xml

Saves Lines Blank lines Bytes
0 144 10 9,062
1 192 67 9,938
2 254 129 10,900
3 316 191 11,862
4 378 253 12,824

Roughly 60 blank lines and 960 bytes per save. Every change made through the console or the REST API stores the file, and each save is preceded by a numbered backup, so each bloated generation is also kept on disk.

Fix

Discard the layout whitespace when the file is parsed, leaving the serializer as the only thing deciding the layout. Done on load rather than on save so that every write path benefits.

After the fix the same run is stable at 115 lines and 7,928 bytes, byte identical across five saves. A file that has already accumulated blank lines is also tidied the next time it is stored, so an affected deployment repairs itself rather than needing the file cleaned up by hand.

Only text nodes that are entirely whitespace are removed, using //text()[normalize-space(.) = ''], so no value can be affected. Nothing in a partnerships file carries text content in any case as every value is held in an attribute.

Testing

177 tests pass, 4 new. Removing the fix fails two of them.

  • repeatedSavesDoNotGrowTheFile requires five consecutive saves to produce a byte identical file
  • aFileThatAlreadyAccumulatedBlankLinesIsTidiedOnTheNextSave takes a file damaged the way the bug damages it and requires the next save to clean it
  • savingDoesNotChangeAnyElementOrAttribute flattens the document into every element with its sorted attributes and values and requires the lists to be identical across a save, so any change to the data would fail
  • theStoredFileIsStillReadableAndIndented checks the output is still well formed and still indented

org.openas2.upgrades.MigratePollingModuleConfig writes its output the same way and has the same defect, but it is run once by hand and its partnerships output is tidied by the first load after this change, so it is left alone.

The parser keeps the newlines and indentation between elements as text nodes.
The serializer that stores the partnerships sets INDENT so it adds indentation
of its own, and it cannot remove the nodes that are already there, so storing a
document read from disk wrote the original whitespace plus a fresh layer of it.

Every save therefore grew the file. Measured against the shipped partnerships
file, five saves took it from 10 blank lines and 9062 bytes to 253 blank lines
and 12824 bytes, adding roughly 60 lines each time with no bound. Any change
through the console or the API stores the file, and each save is preceded by a
numbered backup, so the growth accumulated over the life of a deployment.

The layout whitespace is now discarded when the file is parsed, leaving the
serializer as the only thing deciding the layout. Saving is idempotent as a
result, and a file that has already accumulated blank lines is tidied the next
time it is stored rather than needing to be repaired by hand.

Only text nodes that are entirely whitespace are removed, so no value can be
affected. Nothing in a partnerships file carries text content in any case:
every value is held in an attribute.

Note that org.openas2.upgrades.MigratePollingModuleConfig writes its output the
same way and has the same defect, but it runs once by hand and its partnerships
output is tidied by the first load after this change, so it is left alone.

@uhurusurfa uhurusurfa left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀

@uhurusurfa
uhurusurfa merged commit 95f056c into OpenAS2:master Sep 16, 2026
11 checks passed
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.

2 participants