From 95a4718824cf2fb15ea86e80fc2b87f6896054e1 Mon Sep 17 00:00:00 2001 From: Manfred Baedke Date: Thu, 7 Aug 2025 13:51:28 +0200 Subject: [PATCH 1/2] OAK-11845: Make SecureNodeBuilder thread safe done. --- .../org/apache/jackrabbit/oak/core/SecureNodeBuilder.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/oak-core/src/main/java/org/apache/jackrabbit/oak/core/SecureNodeBuilder.java b/oak-core/src/main/java/org/apache/jackrabbit/oak/core/SecureNodeBuilder.java index 3f04699e15b..1490b114606 100644 --- a/oak-core/src/main/java/org/apache/jackrabbit/oak/core/SecureNodeBuilder.java +++ b/oak-core/src/main/java/org/apache/jackrabbit/oak/core/SecureNodeBuilder.java @@ -156,7 +156,7 @@ public boolean isReplaced(String name) { return builder.isReplaced(name) && !isNew(name); } - public void baseChanged() { + public synchronized void baseChanged() { Validate.checkState(parent == null); treePermission = null; // trigger re-evaluation rootPermission = null; @@ -349,7 +349,7 @@ public Blob createBlob(InputStream stream) throws IOException { * @return The permissions for this tree. */ @NotNull - private TreePermission getTreePermission() { + private synchronized TreePermission getTreePermission() { if (treePermission == null || rootPermission != rootBuilder.treePermission) { NodeState base = builder.getBaseState(); From e84e04dd9ddff79673ae3f200ab5739c8d780b2e Mon Sep 17 00:00:00 2001 From: Manfred Baedke Date: Thu, 7 Aug 2025 17:10:34 +0200 Subject: [PATCH 2/2] OAK-11845: Avoid race conditions in SecureNodeBuilder#getTreePermissions() Done. --- .../oak/core/SecureNodeBuilder.java | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/oak-core/src/main/java/org/apache/jackrabbit/oak/core/SecureNodeBuilder.java b/oak-core/src/main/java/org/apache/jackrabbit/oak/core/SecureNodeBuilder.java index 1490b114606..3a9d1c91615 100644 --- a/oak-core/src/main/java/org/apache/jackrabbit/oak/core/SecureNodeBuilder.java +++ b/oak-core/src/main/java/org/apache/jackrabbit/oak/core/SecureNodeBuilder.java @@ -88,6 +88,8 @@ class SecureNodeBuilder implements NodeBuilder { */ private TreePermission rootPermission = null; // initialized lazily + private volatile boolean reevaluatePermissions = true; + /** * Create the {@code SecureNodeBuilder} for the root node. * @@ -156,10 +158,9 @@ public boolean isReplaced(String name) { return builder.isReplaced(name) && !isNew(name); } - public synchronized void baseChanged() { + public void baseChanged() { Validate.checkState(parent == null); - treePermission = null; // trigger re-evaluation - rootPermission = null; + reevaluatePermissions = true; } @Override @@ -349,9 +350,8 @@ public Blob createBlob(InputStream stream) throws IOException { * @return The permissions for this tree. */ @NotNull - private synchronized TreePermission getTreePermission() { - if (treePermission == null - || rootPermission != rootBuilder.treePermission) { + private TreePermission getTreePermission() { + if (isPermissionEvaluationNeeded()) { NodeState base = builder.getBaseState(); String msg = "see OAK-11790 and OAK-11843"; if (parent == null) { @@ -364,10 +364,18 @@ private synchronized TreePermission getTreePermission() { treePermission = Objects.requireNonNull(parentTreePermission.getChildPermission(name, base), msg); rootPermission = parent.rootPermission; } + reevaluatePermissions = false; } return treePermission; } + private boolean isPermissionEvaluationNeeded() { + if (rootPermission != rootBuilder.treePermission) { + reevaluatePermissions = true; + } + return reevaluatePermissions; + } + private static boolean isType(@Nullable PropertyState property, Type type) { Type t = (property == null) ? null : property.getType(); return t == type;