From b4fe4ded0c16fb2dc6a52c2a4139375d5f5c2de3 Mon Sep 17 00:00:00 2001 From: Serhii Plyhun Date: Fri, 10 Oct 2025 15:12:08 +0200 Subject: [PATCH 1/2] SUP-19037: Improve stream performance + avoid deadlocks (backport) --- .../java/com/gentics/mesh/verticle/BinaryCheckVerticle.java | 2 +- .../changelog/highlevel/HighLevelChangelogSystemImpl.java | 2 +- .../mesh/core/data/service/AbstractWebRootService.java | 4 +--- .../mesh/graphdb/cluster/OrientDBClusterManagerImpl.java | 2 +- .../gentics/mesh/distributed/coordinator/MasterElector.java | 6 +++--- .../mesh/search/index/node/NodeIndexHandlerImpl.java | 2 +- .../com/gentics/mesh/core/data/dao/PersistingNodeDao.java | 6 +++--- .../java/com/gentics/mesh/core/data/impl/BranchImpl.java | 4 ++-- .../gentics/mesh/core/rest/schema/FieldSchemaContainer.java | 4 ++-- .../gentics/mesh/core/rest/schema/LanguageOverrideUtil.java | 2 +- .../com/gentics/mesh/core/rest/schema/MicroschemaModel.java | 2 +- .../main/java/com/gentics/mesh/auth/util/MappingHelper.java | 2 +- .../com/gentics/mesh/graphql/type/AbstractTypeProvider.java | 4 ++-- .../com/gentics/mesh/graphql/type/NodeTypeProvider.java | 2 +- 14 files changed, 21 insertions(+), 23 deletions(-) diff --git a/common/src/main/java/com/gentics/mesh/verticle/BinaryCheckVerticle.java b/common/src/main/java/com/gentics/mesh/verticle/BinaryCheckVerticle.java index 28f7d1a2a7..53159241c1 100644 --- a/common/src/main/java/com/gentics/mesh/verticle/BinaryCheckVerticle.java +++ b/common/src/main/java/com/gentics/mesh/verticle/BinaryCheckVerticle.java @@ -119,7 +119,7 @@ private void performBinaryCheck(Long id) { ContentDao contentDao = tx.contentDao(); tx.binaryDao().findByCheckStatus(BinaryCheckStatus.POSTPONED).runInExistingTx(tx).forEach(binary -> { - Optional field = tx.binaryDao().findFields(binary).stream().findFirst(); + Optional field = tx.binaryDao().findFields(binary).stream().findAny(); if (field.isEmpty()) { return; diff --git a/core/src/main/java/com/gentics/mesh/changelog/highlevel/HighLevelChangelogSystemImpl.java b/core/src/main/java/com/gentics/mesh/changelog/highlevel/HighLevelChangelogSystemImpl.java index be43df74ce..9d8eb9d5bc 100644 --- a/core/src/main/java/com/gentics/mesh/changelog/highlevel/HighLevelChangelogSystemImpl.java +++ b/core/src/main/java/com/gentics/mesh/changelog/highlevel/HighLevelChangelogSystemImpl.java @@ -93,7 +93,7 @@ public boolean requiresChanges(ChangelogDao dao, Predicate !isApplied(dao, change)).findFirst().isPresent(); + return stream.filter(change -> !isApplied(dao, change)).findAny().isPresent(); }); } diff --git a/core/src/main/java/com/gentics/mesh/core/data/service/AbstractWebRootService.java b/core/src/main/java/com/gentics/mesh/core/data/service/AbstractWebRootService.java index 77be22b56d..8a295ea2cf 100644 --- a/core/src/main/java/com/gentics/mesh/core/data/service/AbstractWebRootService.java +++ b/core/src/main/java/com/gentics/mesh/core/data/service/AbstractWebRootService.java @@ -1,6 +1,5 @@ package com.gentics.mesh.core.data.service; -import java.util.Iterator; import java.util.Optional; import java.util.Stack; @@ -15,7 +14,6 @@ import com.gentics.mesh.core.db.Database; import com.gentics.mesh.core.db.Tx; import com.gentics.mesh.core.rest.common.ContainerType; -import com.gentics.mesh.core.result.Result; import com.gentics.mesh.core.webroot.PathPrefixUtil; import com.gentics.mesh.path.Path; import com.gentics.mesh.path.impl.PathImpl; @@ -76,7 +74,7 @@ public Path findByProjectPath(InternalActionContext ac, String path, ContainerTy // Handle path to project root (baseNode) if ("/".equals(strippedPath) || strippedPath.isEmpty()) { - Optional container = contentDao.getFieldContainers(baseNode, branch, type).stream().findFirst(); + Optional container = contentDao.getFieldContainers(baseNode, branch, type).stream().findAny(); if (container.isPresent()) { nodePath.addSegment(new PathSegmentImpl(container.get(), null, null, "/")); stack.push("/"); diff --git a/databases/orientdb/src/main/java/com/gentics/mesh/graphdb/cluster/OrientDBClusterManagerImpl.java b/databases/orientdb/src/main/java/com/gentics/mesh/graphdb/cluster/OrientDBClusterManagerImpl.java index 1b40191ab0..c63ac1f96b 100644 --- a/databases/orientdb/src/main/java/com/gentics/mesh/graphdb/cluster/OrientDBClusterManagerImpl.java +++ b/databases/orientdb/src/main/java/com/gentics/mesh/graphdb/cluster/OrientDBClusterManagerImpl.java @@ -586,7 +586,7 @@ public Optional getInstanceDiskQuotaExceeded() { } else { return hazelcastPlugin.getHazelcastInstance().getCluster().getMembers().stream() .filter(m -> m.getBooleanAttribute(MESH_MEMBER_DISK_QUOTA_EXCEEDED) == Boolean.TRUE) - .map(m -> m.getUuid()).findFirst(); + .map(m -> m.getUuid()).findAny(); } } diff --git a/distributed-coordinator/src/main/java/com/gentics/mesh/distributed/coordinator/MasterElector.java b/distributed-coordinator/src/main/java/com/gentics/mesh/distributed/coordinator/MasterElector.java index 048a154e93..5ffce219fd 100644 --- a/distributed-coordinator/src/main/java/com/gentics/mesh/distributed/coordinator/MasterElector.java +++ b/distributed-coordinator/src/main/java/com/gentics/mesh/distributed/coordinator/MasterElector.java @@ -146,7 +146,7 @@ private void electMaster() { log.info("Locked for master election"); Optional foundMaster = cluster.getMembers().stream() .filter(m -> isMaster(m)) - .findFirst(); + .findAny(); boolean hasMaster = foundMaster.isPresent(); boolean isElectible = isElectable(localMember()); if (!hasMaster && isElectible) { @@ -187,7 +187,7 @@ private boolean isElectable(Member member) { if (clusterOptions.getCoordinatorTopology() == CoordinationTopology.UNMANAGED) { ClusterConfigResponse config = database.loadClusterConfig(); - Optional databaseServer = config.getServers().stream().filter(s -> s.getName().equals(name)).findFirst(); + Optional databaseServer = config.getServers().stream().filter(s -> s.getName().equals(name)).findAny(); if (databaseServer.isPresent()) { // Replicas are not eligible for master election ServerRole role = databaseServer.get().getRole(); @@ -274,7 +274,7 @@ protected void findCurrentMaster() { Cluster cluster = hazelcast.get().getCluster(); Optional master = cluster.getMembers().stream() .filter(m -> isMaster(m)) - .findFirst(); + .findAny(); if (master.isPresent()) { masterMember = master.get(); log.info("Updated master member {" + masterMember.getStringAttribute(MESH_NODE_NAME_ATTR) + "}"); diff --git a/elasticsearch/src/main/java/com/gentics/mesh/search/index/node/NodeIndexHandlerImpl.java b/elasticsearch/src/main/java/com/gentics/mesh/search/index/node/NodeIndexHandlerImpl.java index 2337de2051..ecc48b3aaa 100644 --- a/elasticsearch/src/main/java/com/gentics/mesh/search/index/node/NodeIndexHandlerImpl.java +++ b/elasticsearch/src/main/java/com/gentics/mesh/search/index/node/NodeIndexHandlerImpl.java @@ -408,7 +408,7 @@ protected void processHits(JsonArray hits, Map versions) { private Flowable diffAndSync(HibProject project, HibBranch branch, HibSchemaVersion version, ContainerType type, Optional indexPattern) { // if an index pattern is given, check whether any index matches the pattern if (indexPattern.isPresent() && !getIndexNames(project, branch, version, type).stream() - .filter(indexName -> indexPattern.orElse(MATCH_ALL).matcher(indexName).matches()).findFirst() + .filter(indexName -> indexPattern.orElse(MATCH_ALL).matcher(indexName).matches()).findAny() .isPresent()) { return Flowable.empty(); } diff --git a/mdm/common/src/main/java/com/gentics/mesh/core/data/dao/PersistingNodeDao.java b/mdm/common/src/main/java/com/gentics/mesh/core/data/dao/PersistingNodeDao.java index cbd974955e..055cb2eb40 100644 --- a/mdm/common/src/main/java/com/gentics/mesh/core/data/dao/PersistingNodeDao.java +++ b/mdm/common/src/main/java/com/gentics/mesh/core/data/dao/PersistingNodeDao.java @@ -1214,7 +1214,7 @@ default Map getPaths(Collection sourceNodes, InternalA @Override default Map getPaths(Collection sourceNodes, String branchUuid, InternalActionContext ac, ContainerType type, String... languageTags) { BranchDao branchDao = Tx.get().branchDao(); - HibBranch branch = sourceNodes.stream().map(node -> branchDao.findByUuid(node.getProject(), branchUuid)).findFirst().orElse(null); + HibBranch branch = sourceNodes.stream().map(node -> branchDao.findByUuid(node.getProject(), branchUuid)).findAny().orElse(null); return getPaths(sourceNodes, branch, ac, type, languageTags); } @@ -1265,7 +1265,7 @@ default Map getPaths(Collection sourceNodes, HibBranch String fallbackPath = null; if (containerForUrlFieldValues != null) { fallbackPath = contentDao.getUrlFieldValues(containerForUrlFieldValues) - .findFirst() + .findAny() .map(path -> getWithSanitizedPathPrefix(branch, builder -> builder.append(path))) .orElse(null); } @@ -1394,7 +1394,7 @@ private String getUrlFieldPath(HibNode node, HibBranch branch, ContainerType typ return Stream.of(languages) .flatMap(language -> Stream.ofNullable(contentDao.getFieldContainer(node, language, branch != null ? branch.getUuid() : null, type))) .flatMap(contentDao::getUrlFieldValues) - .findFirst() + .findAny() .map(path -> getWithSanitizedPathPrefix(branch, builder -> builder.append(path))) .orElse(null); } diff --git a/mdm/orientdb-wrapper/src/main/java/com/gentics/mesh/core/data/impl/BranchImpl.java b/mdm/orientdb-wrapper/src/main/java/com/gentics/mesh/core/data/impl/BranchImpl.java index b41b847a09..0cb3baebaa 100644 --- a/mdm/orientdb-wrapper/src/main/java/com/gentics/mesh/core/data/impl/BranchImpl.java +++ b/mdm/orientdb-wrapper/src/main/java/com/gentics/mesh/core/data/impl/BranchImpl.java @@ -230,7 +230,7 @@ public HibSchemaVersion findLatestSchemaVersion(HibSchema schemaContainer) { String v1 = o1.getProperty(GraphFieldSchemaContainerVersion.VERSION_PROPERTY_KEY); String v2 = o2.getProperty(GraphFieldSchemaContainerVersion.VERSION_PROPERTY_KEY); return VersionUtil.compareVersions(v2, v1); - }).findFirst().orElse(null); + }).findAny().orElse(null); return graphVersion; } @@ -244,7 +244,7 @@ public HibMicroschemaVersion findLatestMicroschemaVersion(HibMicroschema schemaC String v1 = o1.getProperty(GraphFieldSchemaContainerVersion.VERSION_PROPERTY_KEY); String v2 = o2.getProperty(GraphFieldSchemaContainerVersion.VERSION_PROPERTY_KEY); return VersionUtil.compareVersions(v2, v1); - }).findFirst().orElse(null); + }).findAny().orElse(null); } @Override diff --git a/rest-model/src/main/java/com/gentics/mesh/core/rest/schema/FieldSchemaContainer.java b/rest-model/src/main/java/com/gentics/mesh/core/rest/schema/FieldSchemaContainer.java index 60db5ac69d..7cac4d4710 100644 --- a/rest-model/src/main/java/com/gentics/mesh/core/rest/schema/FieldSchemaContainer.java +++ b/rest-model/src/main/java/com/gentics/mesh/core/rest/schema/FieldSchemaContainer.java @@ -79,7 +79,7 @@ public interface FieldSchemaContainer extends RestModel { * @return */ default FieldSchema getField(String fieldName) { - return getFields().stream().filter(f -> f.getName().equals(fieldName)).findFirst().orElse(null); + return getFields().stream().filter(f -> f.getName().equals(fieldName)).findAny().orElse(null); } /** @@ -90,7 +90,7 @@ default FieldSchema getField(String fieldName) { * @return */ default T getField(String fieldName, Class classOfT) { - return classOfT.cast(getFields().stream().filter(f -> f.getName().equals(fieldName)).findFirst().orElse(null)); + return classOfT.cast(getFields().stream().filter(f -> f.getName().equals(fieldName)).findAny().orElse(null)); } /** diff --git a/rest-model/src/main/java/com/gentics/mesh/core/rest/schema/LanguageOverrideUtil.java b/rest-model/src/main/java/com/gentics/mesh/core/rest/schema/LanguageOverrideUtil.java index e1b91e9e6c..0fbc409904 100644 --- a/rest-model/src/main/java/com/gentics/mesh/core/rest/schema/LanguageOverrideUtil.java +++ b/rest-model/src/main/java/com/gentics/mesh/core/rest/schema/LanguageOverrideUtil.java @@ -32,7 +32,7 @@ private LanguageOverrideUtil() { public static void validateLanguageOverrides(JsonObject settings) { findLanguages(settings) .filter(unique().negate()) - .findFirst() + .findAny() .ifPresent(duplicateLanguage -> { throw error(BAD_REQUEST, "error_language_duplicate_override", duplicateLanguage); }); diff --git a/rest-model/src/main/java/com/gentics/mesh/core/rest/schema/MicroschemaModel.java b/rest-model/src/main/java/com/gentics/mesh/core/rest/schema/MicroschemaModel.java index b79859ba17..67b65d1f92 100644 --- a/rest-model/src/main/java/com/gentics/mesh/core/rest/schema/MicroschemaModel.java +++ b/rest-model/src/main/java/com/gentics/mesh/core/rest/schema/MicroschemaModel.java @@ -29,7 +29,7 @@ default void validate() { } } return false; - }).findFirst(); + }).findAny(); if (firstDisallowed.isPresent()) { FieldSchema field = firstDisallowed.get(); String typeInfo = field.getType(); diff --git a/services/jwt-auth/src/main/java/com/gentics/mesh/auth/util/MappingHelper.java b/services/jwt-auth/src/main/java/com/gentics/mesh/auth/util/MappingHelper.java index 2a0f9587e1..a54a2780e1 100644 --- a/services/jwt-auth/src/main/java/com/gentics/mesh/auth/util/MappingHelper.java +++ b/services/jwt-auth/src/main/java/com/gentics/mesh/auth/util/MappingHelper.java @@ -186,7 +186,7 @@ public void load() { */ public boolean areMappedEntitiesMissing() { return entitiesByName.entrySet().stream().filter(entry -> mappedNames.contains(entry.getKey())) - .filter(entry -> entry.getValue() == null).findFirst().isPresent(); + .anyMatch(entry -> entry.getValue() == null); } /** diff --git a/verticles/graphql/src/main/java/com/gentics/mesh/graphql/type/AbstractTypeProvider.java b/verticles/graphql/src/main/java/com/gentics/mesh/graphql/type/AbstractTypeProvider.java index f4bed60f64..87e4a0210e 100644 --- a/verticles/graphql/src/main/java/com/gentics/mesh/graphql/type/AbstractTypeProvider.java +++ b/verticles/graphql/src/main/java/com/gentics/mesh/graphql/type/AbstractTypeProvider.java @@ -422,8 +422,8 @@ protected HibBaseElement handleBranchSchema(DataFetchingEnvironment env) { return handleUuidNameArgsNoPerm(env, uuid -> schemas.filter(schema -> { HibSchema container = schema.getSchemaContainer(); return container.getUuid().equals(uuid) && userDao.hasPermission(gc.getUser(), container, READ_PERM); - }).findFirst().get(), name -> schemas.filter(schema -> schema.getName().equals(name) && userDao.hasPermission(gc.getUser(), schema - .getSchemaContainer(), READ_PERM)).findFirst().get()); + }).findAny().get(), name -> schemas.filter(schema -> schema.getName().equals(name) && userDao.hasPermission(gc.getUser(), schema + .getSchemaContainer(), READ_PERM)).findAny().get()); } protected Page handleBranchSchemas(DataFetchingEnvironment env) { diff --git a/verticles/graphql/src/main/java/com/gentics/mesh/graphql/type/NodeTypeProvider.java b/verticles/graphql/src/main/java/com/gentics/mesh/graphql/type/NodeTypeProvider.java index 2ff1064165..f011ef703a 100644 --- a/verticles/graphql/src/main/java/com/gentics/mesh/graphql/type/NodeTypeProvider.java +++ b/verticles/graphql/src/main/java/com/gentics/mesh/graphql/type/NodeTypeProvider.java @@ -607,7 +607,7 @@ public Versioned> createNodeInterfaceFields(GraphQL return contentDao.getFieldContainers(node, tx.getBranch(gc), DRAFT).stream().filter(c -> { String lang = c.getLanguageTag(); return lang.equals(languageTag); - }).findFirst().map(contentDao::versions).orElse(null); + }).findAny().map(contentDao::versions).orElse(null); }).build(), // .language From 5e8b260cc293bf1c443c8f9ceaf53730efb6d9ef Mon Sep 17 00:00:00 2001 From: Serhii Plyhun Date: Fri, 10 Oct 2025 15:38:10 +0200 Subject: [PATCH 2/2] Changelog --- changelog/src/changelog/entries/2025/10/8504.SUP-19037.bugfix | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog/src/changelog/entries/2025/10/8504.SUP-19037.bugfix diff --git a/changelog/src/changelog/entries/2025/10/8504.SUP-19037.bugfix b/changelog/src/changelog/entries/2025/10/8504.SUP-19037.bugfix new file mode 100644 index 0000000000..8b1043d2f9 --- /dev/null +++ b/changelog/src/changelog/entries/2025/10/8504.SUP-19037.bugfix @@ -0,0 +1 @@ +Core: Some refactorings have been made to avoid potential deadlocks or slowdowns on various use cases. \ No newline at end of file