Skip to content

Optimize MetaDataProtoEditor.renameRecordTypes() - #4536

Open
robert-brunel wants to merge 1 commit into
mainfrom
apple/robert-brunel/renameRecordTypes-2
Open

Optimize MetaDataProtoEditor.renameRecordTypes()#4536
robert-brunel wants to merge 1 commit into
mainfrom
apple/robert-brunel/renameRecordTypes-2

Conversation

@robert-brunel

@robert-brunel robert-brunel commented Aug 28, 2026

Copy link
Copy Markdown
Contributor
  • Replace the naive O(N²) implementation of renameRecordTypes(), which renames the types one by one via renameRecordType(), with an efficient batched version that applies all renames in one go.
  • Cleanly split the per-rename validation from the actual mutation throughout, so that the whole batch gets validated before anything is mutated.
  • Add a RecordTypeRenames data structure that indexes renames by fully qualified name to avoid having to scan all renames per item. This brings what would otherwise still be an O(N²) algorithm down to O(N).
  • Leave renameRecordType() itself untouched for the time being. It will be simplified in a subsequent change by “rebasing” it on the utility methods introduced here.

The batched implementation performs the costly compilation of the FileDescriptor exactly once (via Descriptors.FileDescriptor.buildFrom(), from the original proto) and applies the name mapping in a single walk of the builder. The trivial implementation, by contrast, performs a recompilation of the entire records FileDescriptor plus a full records.toBuilder() deep-copy in each iteration of the loop over the record types. In the common use case where all top-level record types are to be renamed, that means O(N) descriptor compilations for N record types.

Applying multiple renames in the batched manner is equivalent to applying them one-by-one, provided that the name mapping defined by the given renamer is collision-free. The batched implementation validates the mapping upfront. This allows it to provide a stronger exception safety guarantee. If the mapping is invalid, an exception will be thrown before any of the renames is performed. The one-by-one implementation, by contrast, may raise an exception halfway through; and that may depend on the order in which the renames are applied.

Testing

  • Cross-check renameRecordType() and renameRecordTypes() against each other throughout the existing test suite.
  • Add dedicated tests for every MetaDataException reachable from renameRecordTypes(), plus a couple of previously unexercised edge cases.
  • Fix an unrelated, pre-existing bug in the Joined.json test fixture (a join referenced a nonexistent constituent), uncovered along the way.
  • Add a performance test that renames a large number of record types. In a local ad-hoc experiment with 50 record types, the batched implementation measured about 17× faster than an equivalent one-by-one sequence of renameRecordType() calls (0.1 ms versus 1.5 ms), which is consistent with the O(N) vs. O(N²) difference.

* Replace the naive O(N²) implementation of `renameRecordTypes()`, which renames the types one by one via `renameRecordType()`, with an efficient batched version that applies all renames in one go.
* Cleanly split the per-rename validation from the actual mutation throughout, so that the whole batch gets validated _before_ anything is mutated.
* Add a `RecordTypeRenames` data structure that indexes renames by fully qualified name to avoid having to scan all renames per item. This brings what would otherwise still be an O(N²) algorithm down to O(N).
* Leave `renameRecordType()` itself untouched for the time being. It will be simplified in a subsequent change by “rebasing” it on the utility methods introduced here.

The batched implementation performs the costly compilation of the `FileDescriptor` exactly _once_ (via `Descriptors.FileDescriptor.buildFrom()`, from the original proto) and applies the name mapping in a single walk of the builder. The trivial implementation, by contrast, performs a recompilation of the entire records `FileDescriptor` plus a full `records.toBuilder()` deep-copy _in each iteration_ of the loop over the record types. In the common use case where _all_ top-level record types are to be renamed, that means O(N) descriptor compilations for N record types.

Applying multiple renames in the batched manner is equivalent to applying them one-by-one, _provided that_ the name mapping defined by the given `renamer` is collision-free. The batched implementation validates the mapping upfront. This allows it to provide a stronger exception safety guarantee. If the mapping is invalid, an exception will be thrown before _any_ of the renames is performed. The one-by-one implementation, by contrast, may raise an exception halfway through; and that may depend on the order in which the renames are applied.

### Testing

* Cross-check `renameRecordType()` and `renameRecordTypes()` against each other throughout the existing test suite.
* Add dedicated tests for every `MetaDataException` reachable from `renameRecordTypes()`, plus a couple of previously unexercised edge cases.
* Fix an unrelated, pre-existing bug in the `Joined.json` test fixture (a join referenced a nonexistent constituent), uncovered along the way.
* Add a performance test that renames a large number of record types. In a local ad-hoc experiment with 50 record types, the batched implementation measured about 17× faster than an equivalent one-by-one sequence of `renameRecordType()` calls (0.1 ms versus 1.5 ms), which is consistent with the O(N) vs. O(N²) difference.
@robert-brunel robert-brunel added performance Performance issues enhancement New feature or request labels Aug 28, 2026
@robert-brunel robert-brunel changed the title apple/robert brunel/renameRecordTypes 2 Optimize MetaDataProtoEditor.renameRecordTypes() Aug 28, 2026
@robert-brunel robert-brunel self-assigned this Aug 28, 2026
@robert-brunel
robert-brunel marked this pull request as ready for review August 28, 2026 19:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request performance Performance issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant