+
Skip to content

Conversation

ahus1
Copy link
Contributor

@ahus1 ahus1 commented Oct 10, 2025

Closes #43362

@ahus1 ahus1 self-assigned this Oct 10, 2025
@ahus1 ahus1 force-pushed the is-43362-remove-em-flush-calls branch from 48b6395 to 5eabd3e Compare October 10, 2025 13:48
Closes keycloak#43362

Signed-off-by: Alexander Schwartz <alexander.schwartz@ibm.com>
@ahus1 ahus1 force-pushed the is-43362-remove-em-flush-calls branch from 5eabd3e to 49dbbc5 Compare October 10, 2025 14:46
@ahus1
Copy link
Contributor Author

ahus1 commented Oct 10, 2025

@shawkins - may I ask you to review this PR, or should I ask a different team? Thanks!

@ahus1 ahus1 marked this pull request as ready for review October 10, 2025 17:27
@ahus1 ahus1 requested a review from a team as a code owner October 10, 2025 17:27
@ahus1 ahus1 enabled auto-merge (squash) October 10, 2025 17:27
Copy link
Contributor

@shawkins shawkins left a comment

Choose a reason for hiding this comment

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

LGTM, just added a couple of general thoughts. Ideally we can revisit the excess flushing more systematically. If I recall it was roughly doubling the time that it takes to perform an import.

action.setPriority(model.getPriority());
realm.getRequiredActionProviders().add(action);
em.persist(action);
em.flush();
Copy link
Contributor

Choose a reason for hiding this comment

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

This seems fine. In general there are a lot of flushes in RealmAdapter that seem ad hoc beyond the pattern of persist / flush / detach.

Comment on lines +1323 to +1343
Set<ClientScopeClientMappingEntity> clientScopeEntities = clientScopes.stream()
.filter(clientScope -> !existingClientScopes.containsKey(clientScope.getName()))
.filter(clientScope -> {
if (clientScope.getProtocol() == null) {
// set default protocol if not set. Otherwise, we will get a NullPointer
clientScope.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
}
return acceptedClientProtocols.contains(clientScope.getProtocol());
})
.map(clientScope -> {
ClientScopeClientMappingEntity entity = new ClientScopeClientMappingEntity();
entity.setClientScopeId(clientScope.getId());
entity.setClientId(client.getId());
entity.setDefaultScope(defaultScope);
em.persist(entity);
return entity;
}).collect(Collectors.toSet());
if (!clientScopeEntities.isEmpty()) {
em.flush();
clientScopeEntities.forEach(entity -> em.detach(entity));
}
Copy link
Contributor

Choose a reason for hiding this comment

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

In situations where you have less direct control over the transitive calls, the pattern using the EntityManagers logic looks like:

Suggested change
Set<ClientScopeClientMappingEntity> clientScopeEntities = clientScopes.stream()
.filter(clientScope -> !existingClientScopes.containsKey(clientScope.getName()))
.filter(clientScope -> {
if (clientScope.getProtocol() == null) {
// set default protocol if not set. Otherwise, we will get a NullPointer
clientScope.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
}
return acceptedClientProtocols.contains(clientScope.getProtocol());
})
.map(clientScope -> {
ClientScopeClientMappingEntity entity = new ClientScopeClientMappingEntity();
entity.setClientScopeId(clientScope.getId());
entity.setClientId(client.getId());
entity.setDefaultScope(defaultScope);
em.persist(entity);
return entity;
}).collect(Collectors.toSet());
if (!clientScopeEntities.isEmpty()) {
em.flush();
clientScopeEntities.forEach(entity -> em.detach(entity));
}
EntityManagers.runInBatch(session, () -> {
clientScopes.stream()
.filter(clientScope -> !existingClientScopes.containsKey(clientScope.getName()))
.filter(clientScope -> {
if (clientScope.getProtocol() == null) {
// set default protocol if not set. Otherwise, we will get a NullPointer
clientScope.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
}
return acceptedClientProtocols.contains(clientScope.getProtocol());
})
.forEach(clientScope -> {
ClientScopeClientMappingEntity entity = new ClientScopeClientMappingEntity();
entity.setClientScopeId(clientScope.getId());
entity.setClientId(client.getId());
entity.setDefaultScope(defaultScope);
em.persist(entity);
});
}, true);

However that will generally result in 2 flushes though, rather than the single flush that is done here.

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.

Reduce the number entity manager flushes when creating a realm

2 participants

点击 这是indexloc提供的php浏览器服务,不要输入任何密码和下载