Skip to content

[JENKINS-75986] Refactor BuildReferenceMapAdapter#10946

Merged
timja merged 9 commits intojenkinsci:masterfrom
dukhlov:refacrot-lazy-loading-part2
Aug 20, 2025
Merged

[JENKINS-75986] Refactor BuildReferenceMapAdapter#10946
timja merged 9 commits intojenkinsci:masterfrom
dukhlov:refacrot-lazy-loading-part2

Conversation

@dukhlov
Copy link
Contributor

@dukhlov dukhlov commented Aug 11, 2025

See JENKINS-75986.

AbstractLazyLoadRunMap uses BuildReferenceMapAdapter, but there is a lot of code doing a similar job in both classes.
Also, BuildReferenceMapAdapter implements the Map interface instead of extending AbstractMap, which leads to re-implementing trivial methods such as hashCode(), equals(), toString(), and toArray().

Suggested changes for BuildReferenceMapAdapter:

  • Reuse the standard collection base classes (AbstractMap, AbstractSet, AbstractCollection) to avoid redundant code.
  • Treat BuildReferenceMapAdapter strictly as a read-only view (except for the case where iterator remove() delegation is required for core), and remove unnecessary mutation methods.
  • Move the Spliterator customizations from AbstractLazyLoadRunMap into BuildReferenceMapAdapter so that entrySet(), values(), and keySet() implementations can be reused.
  • Align BuildReferenceMapAdapter with the weak consistency semantics of RunMap (e.g., size() may be approximate, but isEmpty() should remain reliable).

Testing done

Manual testing on my local environment,

Proposed changelog entries

  • refactor BuildReferenceMapAdapter to improve code re-usage

Proposed changelog category

/label internal

Proposed upgrade guidelines

N/A

Submitter checklist

  • The Jira issue, if it exists, is well-described.
  • The changelog entries and upgrade guidelines are appropriate for the audience affected by the change (users or developers, depending on the change) and are in the imperative mood (see examples). Fill in the Proposed upgrade guidelines section only if there are breaking changes or changes that may require extra steps from users during upgrade.
  • There is automated testing or an explanation as to why this change has no tests.
  • New public classes, fields, and methods are annotated with @Restricted or have @since TODO Javadocs, as appropriate.
  • New deprecations are annotated with @Deprecated(since = "TODO") or @Deprecated(forRemoval = true, since = "TODO"), if applicable.
  • New or substantially changed JavaScript is not defined inline and does not call eval to ease future introduction of Content Security Policy (CSP) directives (see documentation).
  • For dependency updates, there are links to external changelogs and, if possible, full differentials.
  • For new APIs and extension points, there is a link to at least one consumer.

Desired reviewers

@jglick

Before the changes are marked as ready-for-merge:

Maintainer checklist

  • There are at least two (2) approvals for the pull request and no outstanding requests for change.
  • Conversations in the pull request are over, or it is explicit that a reviewer is not blocking the change.
  • Changelog entries in the pull request title and/or Proposed changelog entries are accurate, human-readable, and in the imperative mood.
  • Proper changelog labels are set so that the changelog can be generated automatically.
  • If the change needs additional upgrade steps from users, the upgrade-guide-needed label is set and there is a Proposed upgrade guidelines section in the pull request title (see example).
  • If it would make sense to backport the change to LTS, a Jira issue must exist, be a Bug or Improvement, and be labeled as lts-candidate to be considered (see query).

@dukhlov dukhlov changed the title test1 Refactror BuildReferenceMapAdapter Aug 11, 2025
@dukhlov dukhlov force-pushed the refacrot-lazy-loading-part2 branch 2 times, most recently from b041c39 to c6fbfab Compare August 11, 2025 18:29
@dukhlov dukhlov force-pushed the refacrot-lazy-loading-part2 branch 10 times, most recently from 45a16a8 to ab0488f Compare August 12, 2025 10:14
@dukhlov dukhlov marked this pull request as ready for review August 12, 2025 13:31
@dukhlov dukhlov changed the title Refactror BuildReferenceMapAdapter [JENKINS-75986] Refactror BuildReferenceMapAdapter Aug 12, 2025
@jglick jglick changed the title [JENKINS-75986] Refactror BuildReferenceMapAdapter [JENKINS-75986] Refactor BuildReferenceMapAdapter Aug 12, 2025
@dukhlov dukhlov force-pushed the refacrot-lazy-loading-part2 branch 3 times, most recently from b082ffd to d6f5d21 Compare August 12, 2025 21:40
…sage

- Reuse the standard collection base classes (AbstractMap, AbstractSet, AbstractCollection)
  to avoid redundant code.
- Treat BuildReferenceMapAdapter strictly as a read-only view (except for the case where iterator
  remove() delegation is required for core), and remove unnecessary mutation methods.
- Move the Spliterator customizations from AbstractLazyLoadRunMap into BuildReferenceMapAdapter
  so that entrySet(), values(), and keySet() implementations can be reused.
- Align BuildReferenceMapAdapter with the weak consistency semantics of RunMap (e.g., size() may be
  approximate, but isEmpty() should remain reliable).
@dukhlov dukhlov force-pushed the refacrot-lazy-loading-part2 branch from d6f5d21 to 48768b1 Compare August 12, 2025 22:25
@timja timja requested a review from a team August 15, 2025 08:29
/**
* Add a <em>new</em> build to the map.
* Do not use when loading existing builds (use {@link #put(Integer, Object)}).
* Do not use when loading existing builds (use {@link #putAll(Map)}).
Copy link
Member

Choose a reason for hiding this comment

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

Left over from the LazyBuildMixIn change in #10759 I guess.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

right

entry = iterator.next();
assertEquals(3, entry.getKey().intValue());
assertEquals("[5, 3, 1]", a.getLoadedBuilds().keySet().toString(), ".next() precomputes the one after that too");
assertEquals("[5, 3]", a.getLoadedBuilds().keySet().toString());
Copy link
Member

Choose a reason for hiding this comment

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

As I understand it, this behavioral change is just being lazier about loading builds from the entry set iterator.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

right

} else
throw new NoSuchElementException();
return entryOf(last);
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

It how it was before - R next = owner.newestBuild(); - was resolved during iterator initialization,
then next() will resolve the next on at place

Comment on lines -404 to -407
for (R i = start; i != end; ) {
i = search(getNumberOf(i) - 1, DESC);
assert i != null;
}
Copy link
Member

Choose a reason for hiding this comment

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

Unclear to me what this loop was even doing (when assertions are disabled).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This code should be removed in scope of #10759. As far as I understood, this loop was loading builds which belong to subMap interval to Index.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Now AbstractLazyLoadRunMap.core (which replaces Index) has all set of build references available on disk by design

if (val == null) {
return null;
}
return removeValue(val) ? val : null;
Copy link
Member

Choose a reason for hiding this comment

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

Would be nicer to remove the key without resolving it, but that would violate the remove signature. Not sure if this is ever actually called on an unloaded build to begin with.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I made BuildReferenceAdapter readonly new of core, all modification expected to be done using core directly. But to reuse navigation collection and it's iterator.remove() functionality, I delegated removing to class, resposible of core modification (AbstractLazyLoadRunMap). The logic we have there relies on removeValue(R) method. So looks like there is noting I can do. Maybe in next PRs if I or somebody else find a way

Copy link
Member

@jglick jglick left a comment

Choose a reason for hiding this comment

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

Minor suggestions, but looks good from what I can tell. I am running some tests in CloudBees CI.

@jglick
Copy link
Member

jglick commented Aug 15, 2025

(remember to push any follow-up changes as new commits to the PR branch rather than force-pushing, to make it easier for reviewers to track progress)

dukhlov and others added 3 commits August 15, 2025 18:40
….java

Co-authored-by: Jesse Glick <jglick@cloudbees.com>
….java

Co-authored-by: Jesse Glick <jglick@cloudbees.com>
@jglick
Copy link
Member

jglick commented Aug 15, 2025

Compilation errors in test module.

Copy link
Member

@jglick jglick left a comment

Choose a reason for hiding this comment

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

(once tests here are fixed, and if I can get this tested in CloudBees CI)

@basil
Copy link
Member

basil commented Aug 15, 2025

This is a great improvement. I don't think I'll have time to review it in detail, but linking #5942 for some history that might be relevant. Thanks again for the great contribution!

Copy link
Member

@jglick jglick left a comment

Choose a reason for hiding this comment

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

Testing in CloudBees CI turned up no obviously related failures.

Copy link
Member

@timja timja left a comment

Choose a reason for hiding this comment

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

Thanks!

/label ready-for-merge


This PR is now ready for merge, after ~24 hours, we will merge it if there's no negative feedback.

Thanks!

@comment-ops-bot comment-ops-bot bot added the ready-for-merge The PR is ready to go, and it will be merged soon if there is no negative feedback label Aug 18, 2025
Copy link

@A1exKH A1exKH left a comment

Choose a reason for hiding this comment

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

LGTM.

@timja timja merged commit af417ec into jenkinsci:master Aug 20, 2025
18 checks passed
@dukhlov dukhlov deleted the refacrot-lazy-loading-part2 branch September 4, 2025 15:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

internal ready-for-merge The PR is ready to go, and it will be merged soon if there is no negative feedback

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants