This is an automated email from the ASF dual-hosted git repository.
mridulpathak pushed a commit to branch release24.09
in repository https://gitbox.apache.org/repos/asf/ofbiz-framework.git
The following commit(s) were added to refs/heads/release24.09 by this push:
new c73b361ca4 Publish the entity-group map only after it is fully loaded
c73b361ca4 is described below
commit c73b361ca4741b5cf0b8f43a2d6e3293704c2ee2
Author: Mridul Pathak <[email protected]>
AuthorDate: Sun Nov 1 13:27:25 2026 +0530
Publish the entity-group map only after it is fully loaded
ModelGroupReader.getGroupCache assigned an empty map to the volatile
groupCache field before filling it, so a concurrent lookup could read a
half-built map, find no group for an entity and fall back to the delegator's
default group, that is, the wrong datasource. The map and the group-name set
are now built in local variables and published once complete. When nothing
could be loaded, getGroupNames now returns the default group instead of the
partial set a failed load used to leave behind.
(cherry picked from commit 1659f436f500f046fbb56116acf442744aec0f99)
---
.../apache/ofbiz/entity/model/ModelGroupReader.java | 21 ++++++++++++---------
1 file changed, 12 insertions(+), 9 deletions(-)
diff --git
a/framework/entity/src/main/java/org/apache/ofbiz/entity/model/ModelGroupReader.java
b/framework/entity/src/main/java/org/apache/ofbiz/entity/model/ModelGroupReader.java
index dbf84d09ca..aaecd97544 100644
---
a/framework/entity/src/main/java/org/apache/ofbiz/entity/model/ModelGroupReader.java
+++
b/framework/entity/src/main/java/org/apache/ofbiz/entity/model/ModelGroupReader.java
@@ -110,9 +110,9 @@ public class ModelGroupReader implements Serializable {
synchronized (ModelGroupReader.class) {
// must check if null again as one of the blocked threads can
still enter
if (this.groupCache == null) {
- // now it's safe
- this.groupCache = new HashMap<>();
- this.groupNames = new TreeSet<>();
+ // build into locals and publish only once complete, so
readers never see a partial map
+ Map<String, String> newGroupCache = new HashMap<>();
+ Set<String> newGroupNames = new TreeSet<>();
UtilTimer utilTimer = new UtilTimer();
// utilTimer.timerString("[ModelGroupReader.getGroupCache]
Before getDocument");
@@ -127,7 +127,6 @@ public class ModelGroupReader implements Serializable {
Debug.logError(e, "Error loading entity group
model", MODULE);
}
if (document == null) {
- this.groupCache = null;
return null;
}
@@ -155,8 +154,8 @@ public class ModelGroupReader implements Serializable {
} catch (GenericEntityConfException e) {
Debug.logWarning(e, "Exception thrown
while getting group name: ", MODULE);
}
- this.groupNames.add(groupName);
- this.groupCache.put(entityName, groupName);
+ newGroupNames.add(groupName);
+ newGroupCache.put(entityName, groupName);
// utilTimer.timerString(" After
entityEntityName -- " + i + " --");
i++;
}
@@ -167,6 +166,9 @@ public class ModelGroupReader implements Serializable {
}
}
utilTimer.timerString("[ModelGroupReader.getGroupCache]
FINISHED - Total Entity-Groups: " + i + " FINISHED");
+ // groupNames first: the volatile write of groupCache
makes both visible to readers that see the map
+ this.groupNames = newGroupNames;
+ this.groupCache = newGroupCache;
}
}
}
@@ -207,15 +209,16 @@ public class ModelGroupReader implements Serializable {
if (delegatorBaseName.indexOf('#') >= 0) {
delegatorBaseName = delegatorBaseName.substring(0,
delegatorBaseName.indexOf('#'));
}
- getGroupCache(delegatorBaseName);
- if (this.groupNames == null) return null;
+ Set<String> loadedGroupNames = getGroupCache(delegatorBaseName) !=
null ? this.groupNames : null;
Set<String> newSet = new HashSet<>();
try {
newSet.add(EntityConfig.getInstance().getDelegator(delegatorBaseName).getDefaultGroupName());
} catch (GenericEntityConfException e) {
Debug.logWarning(e, "Exception thrown while getting delegator
config: ", MODULE);
}
- newSet.addAll(this.groupNames);
+ if (loadedGroupNames != null) {
+ newSet.addAll(loadedGroupNames);
+ }
return newSet;
}