jackrabbit-oak-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From tri...@apache.org
Subject svn commit: r1537792 - in /jackrabbit/oak/trunk: oak-core/src/main/java/org/apache/jackrabbit/oak/security/ oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/ oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization...
Date Fri, 01 Nov 2013 00:59:07 GMT
Author: tripod
Date: Fri Nov  1 00:59:06 2013
New Revision: 1537792

URL: http://svn.apache.org/r1537792
Log:
OAK-1138 Implement global per principal permission entry cache (wip)

Added:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntryCache.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntryProvider.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntryProviderImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStoreImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PrincipalPermissionEntries.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/evaluation/MultipleSessionsACLStabilityTest.java
Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/SecurityProviderImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AuthorizationConfigurationImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/CompiledPermissionImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntry.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionHook.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionProviderImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStore.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionUtil.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/PermissionConstants.java
    jackrabbit/oak/trunk/oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/nodetype/write/builtin_nodetypes.cnd
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/evaluation/AbstractOakCoreTest.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionProviderImplTest.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStoreTest.java
    jackrabbit/oak/trunk/oak-run/run_concurrent.sh

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/SecurityProviderImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/SecurityProviderImpl.java?rev=1537792&r1=1537791&r2=1537792&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/SecurityProviderImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/SecurityProviderImpl.java Fri Nov  1 00:59:06 2013
@@ -17,11 +17,13 @@
 package org.apache.jackrabbit.oak.security;
 
 import java.util.HashSet;
+import java.util.Map;
 import java.util.Set;
 import javax.annotation.Nonnull;
 
 import org.apache.jackrabbit.oak.security.authentication.AuthenticationConfigurationImpl;
 import org.apache.jackrabbit.oak.security.authorization.AuthorizationConfigurationImpl;
+import org.apache.jackrabbit.oak.security.authorization.permission.PermissionEntryCache;
 import org.apache.jackrabbit.oak.security.principal.PrincipalConfigurationImpl;
 import org.apache.jackrabbit.oak.security.privilege.PrivilegeConfigurationImpl;
 import org.apache.jackrabbit.oak.security.user.UserConfigurationImpl;
@@ -38,6 +40,10 @@ public class SecurityProviderImpl implem
 
     private final ConfigurationParameters configuration;
 
+    // we only need 1 instance of authorization config.
+    // todo: maybe provide general mechanism to singletons of configs
+    private AuthorizationConfiguration authorizationConfiguration;
+
     public SecurityProviderImpl() {
         this(ConfigurationParameters.EMPTY);
     }
@@ -89,7 +95,10 @@ public class SecurityProviderImpl implem
 
     @Nonnull
     private AuthorizationConfiguration getAuthorizationConfiguration() {
-        return new AuthorizationConfigurationImpl(this);
+        if (authorizationConfiguration == null) {
+            authorizationConfiguration = new AuthorizationConfigurationImpl(this);
+        }
+        return authorizationConfiguration;
     }
 
     @Nonnull

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AuthorizationConfigurationImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AuthorizationConfigurationImpl.java?rev=1537792&r1=1537791&r2=1537792&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AuthorizationConfigurationImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AuthorizationConfigurationImpl.java Fri Nov  1 00:59:06 2013
@@ -25,8 +25,6 @@ import javax.annotation.Nonnull;
 import javax.jcr.security.AccessControlManager;
 import javax.security.auth.Subject;
 
-import com.google.common.collect.ImmutableList;
-
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Service;
 import org.apache.jackrabbit.oak.api.Root;
@@ -35,6 +33,7 @@ import org.apache.jackrabbit.oak.plugins
 import org.apache.jackrabbit.oak.security.authorization.accesscontrol.AccessControlImporter;
 import org.apache.jackrabbit.oak.security.authorization.accesscontrol.AccessControlManagerImpl;
 import org.apache.jackrabbit.oak.security.authorization.accesscontrol.AccessControlValidatorProvider;
+import org.apache.jackrabbit.oak.security.authorization.permission.PermissionEntryCache;
 import org.apache.jackrabbit.oak.security.authorization.permission.PermissionHook;
 import org.apache.jackrabbit.oak.security.authorization.permission.PermissionProviderImpl;
 import org.apache.jackrabbit.oak.security.authorization.permission.PermissionStoreValidatorProvider;
@@ -53,12 +52,16 @@ import org.apache.jackrabbit.oak.spi.sec
 import org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionProvider;
 import org.apache.jackrabbit.oak.spi.xml.ProtectedItemImporter;
 
+import com.google.common.collect.ImmutableList;
+
 /**
  * Default implementation of the {@code AccessControlConfiguration}.
  */
 @Component()
 @Service({AuthorizationConfiguration.class, SecurityConfiguration.class})
-public class  AuthorizationConfigurationImpl extends ConfigurationBase implements AuthorizationConfiguration {
+public class AuthorizationConfigurationImpl extends ConfigurationBase implements AuthorizationConfiguration {
+
+    private final PermissionEntryCache permissionEntryCache = new PermissionEntryCache();
 
     public AuthorizationConfigurationImpl() {
         super();
@@ -91,7 +94,7 @@ public class  AuthorizationConfiguration
     public List<? extends CommitHook> getCommitHooks(String workspaceName) {
         return ImmutableList.of(
                 new VersionablePathHook(workspaceName),
-                new PermissionHook(workspaceName, getRestrictionProvider()));
+                new PermissionHook(workspaceName, getRestrictionProvider(), permissionEntryCache));
     }
 
     @Override
@@ -129,6 +132,7 @@ public class  AuthorizationConfiguration
     @Nonnull
     @Override
     public PermissionProvider getPermissionProvider(Root root, Set<Principal> principals) {
-        return new PermissionProviderImpl(root, principals, this);
+        return new PermissionProviderImpl(root, principals, this, permissionEntryCache.createLocalCache());
     }
+
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/CompiledPermissionImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/CompiledPermissionImpl.java?rev=1537792&r1=1537791&r2=1537792&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/CompiledPermissionImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/CompiledPermissionImpl.java Fri Nov  1 00:59:06 2013
@@ -20,17 +20,16 @@ import java.security.Principal;
 import java.security.acl.Group;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+
 import javax.annotation.CheckForNull;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterators;
 import org.apache.jackrabbit.JcrConstants;
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Tree;
@@ -55,6 +54,9 @@ import org.apache.jackrabbit.oak.util.Tr
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterators;
+
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.collect.Iterators.concat;
 
@@ -71,60 +73,55 @@ final class CompiledPermissionImpl imple
             Permissions.READ_PROPERTY, PrivilegeBits.BUILT_IN.get(PrivilegeConstants.REP_READ_PROPERTIES),
             Permissions.READ_ACCESS_CONTROL, PrivilegeBits.BUILT_IN.get(PrivilegeConstants.JCR_READ_ACCESS_CONTROL));
 
-    private final Set<Principal> principals;
     private ImmutableRoot root;
-    private final String workspaceName;
 
-    private final Map<String, Tree> userTrees;
-    private final Map<String, Tree> groupTrees;
+    private final String workspaceName;
 
     private final ReadPolicy readPolicy;
 
-    private final PermissionStore userStore;
-    private final PermissionStore groupStore;
+    private PermissionStoreImpl store;
+    private final PermissionEntryProvider userStore;
+    private final PermissionEntryProvider groupStore;
 
     private PrivilegeBitsProvider bitsProvider;
 
-    private CompiledPermissionImpl(@Nonnull Set<Principal> principals,
+    private CompiledPermissionImpl(@Nonnull PermissionEntryCache.Local cache,
+                                   @Nonnull Set<Principal> principals,
                                    @Nonnull ImmutableRoot root, @Nonnull String workspaceName,
-                                   @Nonnull ImmutableTree permissionsTree,
                                    @Nonnull RestrictionProvider restrictionProvider,
                                    @Nonnull Set<String> readPaths) {
-        this.principals = principals;
         this.root = root;
         this.workspaceName = workspaceName;
 
         bitsProvider = new PrivilegeBitsProvider(root);
         readPolicy = (readPaths.isEmpty()) ? EmptyReadPolicy.INSTANCE : new DefaultReadPolicy(readPaths);
 
-        userTrees = new HashMap<String, Tree>(principals.size());
-        groupTrees = new HashMap<String, Tree>(principals.size());
-        if (permissionsTree.exists()) {
-            for (Principal principal : principals) {
-                Tree t = PermissionUtil.getPrincipalRoot(permissionsTree, principal);
-                Map<String, Tree> target = (principal instanceof Group) ? groupTrees : userTrees;
-                if (t.exists()) {
-                    target.put(principal.getName(), t);
-                } else {
-                    target.remove(principal.getName());
-                }
+        // setup
+        store = new PermissionStoreImpl(root, workspaceName, restrictionProvider);
+        Set<String> userNames = new HashSet<String>(principals.size());
+        Set<String> groupNames = new HashSet<String>(principals.size());
+        for (Principal principal : principals) {
+            if (principal instanceof Group) {
+                groupNames.add(principal.getName());
+            } else {
+                userNames.add(principal.getName());
             }
         }
 
-        userStore = PermissionStore.create(userTrees, restrictionProvider);
-        groupStore = PermissionStore.create(groupTrees, restrictionProvider);
+        userStore = new PermissionEntryProviderImpl(store, cache, userNames);
+        groupStore = new PermissionEntryProviderImpl(store, cache, groupNames);
     }
 
     static CompiledPermissions create(@Nonnull ImmutableRoot root, @Nonnull String workspaceName,
                                       @Nonnull Set<Principal> principals,
-                                      @Nonnull AuthorizationConfiguration acConfig) {
-        ImmutableTree permissionsTree = PermissionUtil.getPermissionsRoot(root, workspaceName);
+                                      @Nonnull AuthorizationConfiguration acConfig,
+                                      @Nonnull PermissionEntryCache.Local cache) {
+        Tree permissionsTree = PermissionUtil.getPermissionsRoot(root, workspaceName);
         if (!permissionsTree.exists() || principals.isEmpty()) {
             return NoPermissions.getInstance();
         } else {
             Set<String> readPaths = acConfig.getParameters().getConfigValue(PARAM_READ_PATHS, DEFAULT_READ_PATHS);
-            return new CompiledPermissionImpl(principals, root, workspaceName,
-                    permissionsTree, acConfig.getRestrictionProvider(), readPaths);
+            return new CompiledPermissionImpl(cache, principals, root, workspaceName, acConfig.getRestrictionProvider(), readPaths);
         }
     }
 
@@ -133,40 +130,9 @@ final class CompiledPermissionImpl imple
     public void refresh(@Nonnull ImmutableRoot root, @Nonnull String workspaceName) {
         this.root = root;
         this.bitsProvider = new PrivilegeBitsProvider(root);
-        // test if a permission has been added for those principals that didn't have one before
-
-        ImmutableTree permissionsTree = PermissionUtil.getPermissionsRoot(root, workspaceName);
-        boolean flushUserStore = false;
-        boolean flushGroupStore = false;
-        for (Principal principal : principals) {
-            boolean isGroup = (principal instanceof Group);
-            Map<String, Tree> target = isGroup ? groupTrees : userTrees;
-            Tree principalRoot = PermissionUtil.getPrincipalRoot(permissionsTree, principal);
-            String pName = principal.getName();
-
-            if (principalRoot.exists()) {
-                if (!target.containsKey(pName) || !principalRoot.equals(target.get(pName))) {
-                    target.put(pName, principalRoot);
-                    if (isGroup) {
-                        flushGroupStore = true;
-                    } else {
-                        flushUserStore = true;
-                    }
-                }
-            } else if (target.remove(pName) != null) {
-                if (isGroup) {
-                    flushGroupStore = true;
-                } else {
-                    flushUserStore = true;
-                }
-            }
-        }
-        if (flushUserStore) {
-            userStore.flush();
-        }
-        if (flushGroupStore) {
-            groupStore.flush();
-        }
+        store.flush(root);
+        userStore.flush();
+        groupStore.flush();
     }
 
     @Override
@@ -219,7 +185,7 @@ final class CompiledPermissionImpl imple
 
     @Nonnull
     private TreePermission getParentPermission(@Nonnull Tree tree, int type) {
-        List<Tree> trees = new ArrayList();
+        List<Tree> trees = new ArrayList<Tree>();
         while (!tree.isRoot()) {
             tree = tree.getParent();
             if (tree.exists()) {

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntry.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntry.java?rev=1537792&r1=1537791&r2=1537792&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntry.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntry.java Fri Nov  1 00:59:06 2013
@@ -111,9 +111,9 @@ final class PermissionEntry implements C
                 return -1;
             }
         } else {
-            int depth = PathUtils.getDepth(path);
-            int otherDepth = PathUtils.getDepth(pe.path);
-            if (PathUtils.getDepth(path) == otherDepth) {
+            final int depth = PathUtils.getDepth(path);
+            final int otherDepth = PathUtils.getDepth(pe.path);
+            if (depth == otherDepth) {
                 return path.compareTo(pe.path);
             } else {
                 return (depth < otherDepth) ? 1 : -1;

Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntryCache.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntryCache.java?rev=1537792&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntryCache.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntryCache.java Fri Nov  1 00:59:06 2013
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.security.authorization.permission;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * <code>PermissionEntryCache</code> caches the permission entries of principals. The cache is held globally and contains
+ * a version of the principal permission entries of the session that read them last. each session gets a lazy copy of
+ * the cache and needs to verify if each cached principal permission set still reflects the state that the session sees.
+ * every newly loaded principal permission set can be pushed down to the base cache if it does not exist there yet, or
+ * if it's newer.
+ */
+public class PermissionEntryCache {
+
+    private final Map<String, PrincipalPermissionEntries> base = new ConcurrentHashMap<String, PrincipalPermissionEntries>();
+
+    public Local createLocalCache() {
+        return new Local();
+    }
+
+    public void flush(Set<String> principalNames) {
+        base.keySet().removeAll(principalNames);
+    }
+
+    public class Local {
+
+        private final Map<String, PrincipalPermissionEntries> entries = new HashMap<String, PrincipalPermissionEntries>();
+
+        private final Set<String> verified = new HashSet<String>();
+
+        public Local() {
+            entries.putAll(base);
+        }
+
+        public PrincipalPermissionEntries getEntries(PermissionStore store, String principalName) {
+            PrincipalPermissionEntries ppe = entries.get(principalName);
+            if (ppe == null) {
+                ppe = store.load(principalName);
+                entries.put(principalName, ppe);
+            } else {
+                if (!verified.contains(principalName)) {
+                    if (store.getTimestamp(principalName) != ppe.getTimestamp()) {
+                        ppe = store.load(principalName);
+                        entries.put(principalName, ppe);
+                    }
+                    verified.add(principalName);
+                }
+            }
+
+            // check if base cache has the entries
+            PrincipalPermissionEntries baseppe = base.get(principalName);
+            if (baseppe == null || ppe.getTimestamp() > baseppe.getTimestamp()) {
+                base.put(principalName, ppe);
+            }
+            return ppe;
+        }
+
+        public boolean hasEntries(PermissionStore store, String principalName) {
+            return getNumEntries(store, principalName) > 0;
+        }
+
+        public long getNumEntries(PermissionStore store, String principalName) {
+            return getEntries(store, principalName).getEntries().size();
+        }
+
+        public void flush(Set<String> principalNames) {
+            verified.removeAll(principalNames);
+        }
+
+    }
+}
\ No newline at end of file

Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntryProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntryProvider.java?rev=1537792&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntryProvider.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntryProvider.java Fri Nov  1 00:59:06 2013
@@ -0,0 +1,40 @@
+/*************************************************************************
+ *
+ * ADOBE CONFIDENTIAL
+ * ___________________
+ *
+ *  Copyright ${today.year} Adobe Systems Incorporated
+ *  All Rights Reserved.
+ *
+ * NOTICE:  All information contained herein is, and remains
+ * the property of Adobe Systems Incorporated and its suppliers,
+ * if any.  The intellectual and technical concepts contained
+ * herein are proprietary to Adobe Systems Incorporated and its
+ * suppliers and are protected by trade secret or copyright law.
+ * Dissemination of this information or reproduction of this material
+ * is strictly forbidden unless prior written permission is obtained
+ * from Adobe Systems Incorporated.
+ **************************************************************************/
+package org.apache.jackrabbit.oak.security.authorization.permission;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+import javax.annotation.Nonnull;
+
+import org.apache.jackrabbit.oak.api.Tree;
+
+/**
+ * <code>PermissionEntryProvider</code> provides permission entries for a given set of principals.
+ * It may internally hold a cache to improve performance and usually operates on the permission store.
+ */
+public interface PermissionEntryProvider {
+
+    Iterator<PermissionEntry> getEntryIterator(@Nonnull EntryPredicate predicate);
+
+    Collection<PermissionEntry> getEntries(@Nonnull Tree accessControlledTree);
+
+    Collection<PermissionEntry> getEntries(@Nonnull String accessControlledPath);
+
+    void flush();
+}
\ No newline at end of file

Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntryProviderImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntryProviderImpl.java?rev=1537792&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntryProviderImpl.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntryProviderImpl.java Fri Nov  1 00:59:06 2013
@@ -0,0 +1,180 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.security.authorization.permission;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.AccessControlConstants;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.Iterators;
+
+/**
+ * <code>PermissionEntryProviderImpl</code>...
+ */
+public class PermissionEntryProviderImpl implements PermissionEntryProvider {
+
+    private static final long MAX_SIZE = 250; // TODO define size or make configurable
+
+    private final Set<String> principalNames;
+
+    private final Set<String> existingNames = new HashSet<String>();
+
+    private Map<String, Collection<PermissionEntry>> pathEntryMap;
+
+    private final PermissionStore store;
+
+    private final PermissionEntryCache.Local cache;
+
+    protected PermissionEntryProviderImpl(@Nonnull PermissionStore store, @Nonnull PermissionEntryCache.Local cache,
+                                          @Nonnull Set<String> principalNames) {
+        this.store = store;
+        this.cache = cache;
+        this.principalNames = Collections.unmodifiableSet(principalNames);
+        init();
+    }
+
+    private void init() {
+        long cnt = 0;
+        existingNames.clear();
+        for (String name: principalNames) {
+            if (cnt > MAX_SIZE) {
+                if (cache.hasEntries(store, name)) {
+                    existingNames.add(name);
+                }
+            } else {
+                long n = cache.getNumEntries(store, name);
+                cnt+= n;
+                if (n > 0) {
+                    existingNames.add(name);
+                }
+            }
+        }
+        this.pathEntryMap = cnt < MAX_SIZE
+                ? createMap(cache, store, existingNames)
+                : null;
+    }
+
+    public void flush() {
+        cache.flush(principalNames);
+        init();
+    }
+
+    public Iterator<PermissionEntry> getEntryIterator(@Nonnull EntryPredicate predicate) {
+        if (existingNames.isEmpty()) {
+            return Iterators.emptyIterator();
+        } else {
+            return new EntryIterator(predicate);
+        }
+    }
+
+    public Collection<PermissionEntry> getEntries(@Nonnull Tree accessControlledTree) {
+        if (existingNames.isEmpty()) {
+            return Collections.emptyList();
+        } else if (pathEntryMap != null) {
+            Collection<PermissionEntry> entries = pathEntryMap.get(accessControlledTree.getPath());
+            return (entries != null) ? entries : Collections.<PermissionEntry>emptyList();
+        } else {
+            return (accessControlledTree.hasChild(AccessControlConstants.REP_POLICY)) ?
+                    loadEntries(accessControlledTree.getPath()) :
+                    Collections.<PermissionEntry>emptyList();
+        }
+    }
+
+    @Nonnull
+    public Collection<PermissionEntry> getEntries(@Nonnull String path) {
+        if (existingNames.isEmpty()) {
+            return Collections.emptyList();
+        } else if (pathEntryMap != null) {
+            Collection<PermissionEntry> entries = pathEntryMap.get(path);
+            return (entries != null) ? entries : Collections.<PermissionEntry>emptyList();
+        } else {
+            return loadEntries(path);
+        }
+    }
+
+    @Nonnull
+    private Collection<PermissionEntry> loadEntries(@Nonnull String path) {
+        Collection<PermissionEntry> ret = new TreeSet<PermissionEntry>();
+        for (String name: existingNames) {
+            PrincipalPermissionEntries ppe = cache.getEntries(store, name);
+            ret.addAll(ppe.getEntries(path));
+        }
+        return ret;
+    }
+
+    private static Map<String, Collection<PermissionEntry>> createMap(@Nonnull PermissionEntryCache.Local cache,
+                                                                      @Nonnull PermissionStore store,
+                                                                      @Nonnull Set<String> principalNames) {
+        Map<String, Collection<PermissionEntry>> pathEntryMap = new HashMap<String, Collection<PermissionEntry>>();
+        for (String name: principalNames) {
+            PrincipalPermissionEntries ppe = cache.getEntries(store, name);
+            for (Map.Entry<String, Collection<PermissionEntry>> e: ppe.getEntries().entrySet()) {
+                Collection<PermissionEntry> pathEntries = pathEntryMap.get(e.getKey());
+                if (pathEntries == null) {
+                    pathEntries = new TreeSet<PermissionEntry>(e.getValue());
+                    pathEntryMap.put(e.getKey(), pathEntries);
+                } else {
+                    pathEntries.addAll(e.getValue());
+                }
+            }
+        }
+        return pathEntryMap;
+    }
+
+    private final class EntryIterator extends AbstractEntryIterator {
+
+        private final EntryPredicate predicate;
+
+        // the next oak path for which to retrieve permission entries
+        private String path;
+
+        private EntryIterator(@Nonnull EntryPredicate predicate) {
+            this.predicate = predicate;
+            this.path = Strings.nullToEmpty(predicate.getPath());
+        }
+
+        @CheckForNull
+        protected void seekNext() {
+            for (next = null; next == null; ) {
+                if (nextEntries.hasNext()) {
+                    PermissionEntry pe = nextEntries.next();
+                    if (predicate.apply(pe)) {
+                        next = pe;
+                    }
+                } else {
+                    if (path == null) {
+                        break;
+                    }
+                    nextEntries = getEntries(path).iterator();
+                    path = PermissionUtil.getParentPathOrNull(path);
+                }
+            }
+        }
+    }
+}
\ No newline at end of file

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionHook.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionHook.java?rev=1537792&r1=1537791&r2=1537792&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionHook.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionHook.java Fri Nov  1 00:59:06 2013
@@ -18,6 +18,7 @@ package org.apache.jackrabbit.oak.securi
 
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -83,6 +84,7 @@ public class PermissionHook implements P
 
     private final RestrictionProvider restrictionProvider;
     private final String workspaceName;
+    private final PermissionEntryCache cache;
 
     private NodeBuilder permissionRoot;
     private ReadOnlyNodeTypeManager ntMgr;
@@ -91,9 +93,10 @@ public class PermissionHook implements P
     private Map<String, Acl> modified = new HashMap<String, Acl>();
     private Map<String, Acl> deleted = new HashMap<String, Acl>();
 
-    public PermissionHook(String workspaceName, RestrictionProvider restrictionProvider) {
+    public PermissionHook(String workspaceName, RestrictionProvider restrictionProvider, PermissionEntryCache cache) {
         this.workspaceName = workspaceName;
         this.restrictionProvider = restrictionProvider;
+        this.cache = cache;
     }
 
     @Nonnull
@@ -112,12 +115,14 @@ public class PermissionHook implements P
     }
 
     private void apply() {
+        Set<String> principalNames = new HashSet<String>();
         for (Map.Entry<String, Acl> entry : deleted.entrySet()) {
-            entry.getValue().remove();
+            entry.getValue().remove(principalNames);
         }
         for (Map.Entry<String, Acl> entry : modified.entrySet()) {
-            entry.getValue().update();
+            entry.getValue().update(principalNames);
         }
+        cache.flush(principalNames);
     }
 
     private boolean isACL(@Nonnull Tree tree) {
@@ -291,10 +296,11 @@ public class PermissionHook implements P
             }
         }
 
-        private void remove() {
+        private void remove(Set<String> principalNames) {
             String msg = "Unable to remove permission entry";
             for (String principalName: entries.keySet()) {
                 if (permissionRoot.hasChildNode(principalName)) {
+                    principalNames.add(principalName);
                     NodeBuilder principalRoot = permissionRoot.getChildNode(principalName);
 
                     // find the ACL node that for this path and principal
@@ -343,14 +349,16 @@ public class PermissionHook implements P
                         }
                     }
                     principalRoot.setProperty(REP_NUM_PERMISSIONS, numEntries);
+                    principalRoot.setProperty(REP_TIMESTAMP, System.currentTimeMillis());
                 } else {
                     log.error("{} {}: Principal root missing.", msg, this);
                 }
             }
         }
 
-        private void update() {
+        private void update(Set<String> principalNames) {
             for (String principalName: entries.keySet()) {
+                principalNames.add(principalName);
                 NodeBuilder principalRoot = permissionRoot.child(principalName);
                 if (!principalRoot.hasProperty(JCR_PRIMARYTYPE)) {
                     principalRoot.setProperty(JCR_PRIMARYTYPE, NT_REP_PERMISSION_STORE, Type.NAME);
@@ -397,6 +405,7 @@ public class PermissionHook implements P
                 long numEntries = PermissionUtil.getNumPermissions(principalRoot);
                 numEntries+= updateEntries(parent, entries.get(principalName));
                 principalRoot.setProperty(REP_NUM_PERMISSIONS, numEntries);
+                principalRoot.setProperty(REP_TIMESTAMP, System.currentTimeMillis());
             }
         }
 

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionProviderImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionProviderImpl.java?rev=1537792&r1=1537791&r2=1537792&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionProviderImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionProviderImpl.java Fri Nov  1 00:59:06 2013
@@ -58,7 +58,8 @@ public class PermissionProviderImpl impl
     private ImmutableRoot immutableRoot;
 
     public PermissionProviderImpl(@Nonnull Root root, @Nonnull Set<Principal> principals,
-                                  @Nonnull AuthorizationConfiguration acConfig) {
+                                  @Nonnull AuthorizationConfiguration acConfig,
+                                  @Nonnull PermissionEntryCache.Local cache) {
         this.root = root;
         this.workspaceName = root.getContentSession().getWorkspaceName();
         this.acConfig = acConfig;
@@ -68,7 +69,7 @@ public class PermissionProviderImpl impl
         if (principals.contains(SystemPrincipal.INSTANCE) || isAdmin(principals)) {
             compiledPermissions = AllPermissions.getInstance();
         } else {
-            compiledPermissions = CompiledPermissionImpl.create(immutableRoot, workspaceName, principals, acConfig);
+            compiledPermissions = CompiledPermissionImpl.create(immutableRoot, workspaceName, principals, acConfig, cache);
         }
     }
 

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStore.java?rev=1537792&r1=1537791&r2=1537792&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStore.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStore.java Fri Nov  1 00:59:06 2013
@@ -17,175 +17,26 @@
 package org.apache.jackrabbit.oak.security.authorization.permission;
 
 import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
 import java.util.Map;
-import java.util.TreeSet;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nonnull;
 
-import com.google.common.base.Strings;
-import com.google.common.collect.Iterators;
-import org.apache.jackrabbit.oak.api.Tree;
-import org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.AccessControlConstants;
-import org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionConstants;
-import org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionProvider;
-import org.apache.jackrabbit.oak.util.TreeUtil;
+import javax.annotation.Nonnull;
 
 /**
- * The Permission store reads the principal based access control permissions.
- * One store is currently used to handle 1 set of principal trees (so the compiled
- * permissions use 2 stores, one for the user principals and one for the
- * group principals).
+ * The permission store is used to store and provide access control permissions for principals. It is responsible to
+ * load and store the permissions in an optimal form in the repository and must not cache them.
  */
-final class PermissionStore implements PermissionConstants {
+public interface PermissionStore {
 
-    private static final long MAX_SIZE = 250; // TODO define size or make configurable
+    void load(@Nonnull Collection<PermissionEntry> entries, @Nonnull String principalName, @Nonnull String path);
 
-    private final Map<String, Tree> principalTrees;
-    private final RestrictionProvider restrictionProvider;
-    private Map<String, Collection<PermissionEntry>> pathEntryMap;
-
-    private PermissionStore(@Nonnull Map<String, Tree> principalTrees,
-                            @Nonnull RestrictionProvider restrictionProvider,
-                            boolean doCreateMap) {
-        this.principalTrees = principalTrees;
-        this.restrictionProvider = restrictionProvider;
-        this.pathEntryMap = (doCreateMap) ?
-                createMap(principalTrees.values(), restrictionProvider) : null;
-    }
-
-    static PermissionStore create(@Nonnull Map<String, Tree> principalTrees,
-                                  @Nonnull RestrictionProvider restrictionProvider) {
-        long cnt = 0;
-        if (!principalTrees.isEmpty()) {
-            Iterator<Tree> treeItr = principalTrees.values().iterator();
-            while (treeItr.hasNext() && cnt < MAX_SIZE) {
-                cnt += PermissionUtil.getNumPermissions(treeItr.next());
-            }
-        }
-        return new PermissionStore(principalTrees, restrictionProvider, (cnt < MAX_SIZE));
-    }
-
-    public void flush() {
-        if (pathEntryMap != null) {
-            pathEntryMap = createMap(principalTrees.values(), restrictionProvider);
-        }
-    }
-
-    public Iterator<PermissionEntry> getEntryIterator(@Nonnull EntryPredicate predicate) {
-        if (principalTrees.isEmpty()) {
-            return Iterators.emptyIterator();
-        } else {
-            return new EntryIterator(predicate);
-        }
-    }
-
-    public Collection<PermissionEntry> getEntries(@Nonnull Tree tree) {
-        if (principalTrees.isEmpty()) {
-            return Collections.emptyList();
-        } else if (pathEntryMap != null) {
-            Collection<PermissionEntry> entries = pathEntryMap.get(tree.getPath());
-            return (entries != null) ? entries : Collections.<PermissionEntry>emptyList();
-        } else {
-            return (tree.hasChild(AccessControlConstants.REP_POLICY)) ?
-                    getEntries(tree.getPath()) :
-                    Collections.<PermissionEntry>emptyList();
-        }
-    }
+    void load(@Nonnull Map<String, Collection<PermissionEntry>> entries, @Nonnull String principalName);
 
     @Nonnull
-    private Collection<PermissionEntry> getEntries(@Nonnull String path) {
-        Collection<PermissionEntry> ret = new TreeSet<PermissionEntry>();
-        String name = PermissionUtil.getEntryName(path);
-        for (Map.Entry<String, Tree> principalRoot : principalTrees.entrySet()) {
-            Tree parent = principalRoot.getValue();
-            if (parent.hasChild(name)) {
-                Tree child = parent.getChild(name);
-                if (PermissionUtil.checkACLPath(child, path)) {
-                    loadPermissionEntries(path, ret, child, restrictionProvider);
-                } else {
-                    // check for child node
-                    for (Tree node : child.getChildren()) {
-                        if (PermissionUtil.checkACLPath(node, path)) {
-                            loadPermissionEntries(path, ret, node, restrictionProvider);
-                        }
-                    }
-                }
-            }
-        }
-        return ret;
-    }
-
-    private static Map<String, Collection<PermissionEntry>> createMap(@Nonnull Collection<Tree> principalTrees,
-                                                                      @Nonnull RestrictionProvider restrictionProvider) {
-        Map<String, Collection<PermissionEntry>> pathEntryMap = new HashMap<String, Collection<PermissionEntry>>();
-        for (Tree principalTree : principalTrees) {
-            for (Tree entryTree : principalTree.getChildren()) {
-                loadPermissionEntries(entryTree, pathEntryMap, restrictionProvider);
-            }
-        }
-        return pathEntryMap;
-    }
-
-    private static void loadPermissionEntries(@Nonnull Tree tree,
-                                              @Nonnull Map<String, Collection<PermissionEntry>> pathEntryMap,
-                                              @Nonnull RestrictionProvider restrictionProvider) {
-        String path = TreeUtil.getString(tree, REP_ACCESS_CONTROLLED_PATH);
-        Collection<PermissionEntry> entries = pathEntryMap.get(path);
-        if (entries == null) {
-            entries = new TreeSet<PermissionEntry>();
-            pathEntryMap.put(path, entries);
-        }
-        for (Tree child : tree.getChildren()) {
-            if (child.getName().charAt(0) == 'c') {
-                loadPermissionEntries(child, pathEntryMap, restrictionProvider);
-            } else {
-                entries.add(new PermissionEntry(path, child, restrictionProvider));
-            }
-        }
-    }
-
-    private static void loadPermissionEntries(@Nonnull String path,
-                                              @Nonnull Collection<PermissionEntry> ret,
-                                              @Nonnull Tree tree,
-                                              @Nonnull RestrictionProvider restrictionProvider) {
-        for (Tree ace : tree.getChildren()) {
-            if (ace.getName().charAt(0) != 'c') {
-                ret.add(new PermissionEntry(path, ace, restrictionProvider));
-            }
-        }
-    }
-
-    private final class EntryIterator extends AbstractEntryIterator {
-
-        private final EntryPredicate predicate;
-
-        // the next oak path for which to retrieve permission entries
-        private String path;
-
-        private EntryIterator(@Nonnull EntryPredicate predicate) {
-            this.predicate = predicate;
-            this.path = Strings.nullToEmpty(predicate.getPath());
-        }
-
-        @CheckForNull
-        protected void seekNext() {
-            for (next = null; next == null; ) {
-                if (nextEntries.hasNext()) {
-                    PermissionEntry pe = nextEntries.next();
-                    if (predicate.apply(pe)) {
-                        next = pe;
-                    }
-                } else {
-                    if (path == null) {
-                        break;
-                    }
-                    nextEntries = getEntries(path).iterator();
-                    path = PermissionUtil.getParentPathOrNull(path);
-                }
-            }
-        }
-    }
+    PrincipalPermissionEntries load(@Nonnull String principalName);
+
+    boolean hasPermissionEntries(@Nonnull String principalName);
+
+    long getNumEntries(@Nonnull String principalName);
+
+    long getTimestamp(@Nonnull String principalName);
 }

Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStoreImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStoreImpl.java?rev=1537792&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStoreImpl.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStoreImpl.java Fri Nov  1 00:59:06 2013
@@ -0,0 +1,171 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.security.authorization.permission;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TreeSet;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Root;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionConstants;
+import org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionProvider;
+import org.apache.jackrabbit.oak.util.TreeUtil;
+
+/**
+ * <code>PermissionStoreImpl</code>...
+ */
+public class PermissionStoreImpl implements PermissionStore {
+
+    private Tree permissionsTree;
+
+    private final String workspaceName;
+
+    private final RestrictionProvider restrictionProvider;
+
+    private final Map<String, Tree> principalTreeMap = new HashMap<String, Tree>();
+
+    public PermissionStoreImpl(Root root, String workspaceName, RestrictionProvider restrictionProvider) {
+        this.permissionsTree = PermissionUtil.getPermissionsRoot(root, workspaceName);
+        this.workspaceName = workspaceName;
+        this.restrictionProvider = restrictionProvider;
+    }
+
+    protected void flush(Root root) {
+        this.permissionsTree = PermissionUtil.getPermissionsRoot(root, workspaceName);
+        this.principalTreeMap.clear();
+    }
+
+    @CheckForNull
+    private Tree getPrincipalRoot(@Nonnull String principalName) {
+        if (principalTreeMap.containsKey(principalName)) {
+            return principalTreeMap.get(principalName);
+        } else {
+            Tree principalRoot = PermissionUtil.getPrincipalRoot(permissionsTree, principalName);
+            if (!principalRoot.exists()) {
+                principalRoot = null;
+            }
+            principalTreeMap.put(principalName, principalRoot);
+            return principalRoot;
+        }
+    }
+
+    @Override
+    public void load(@Nonnull Collection<PermissionEntry> entries, @Nonnull String principalName, @Nonnull String path) {
+        Tree principalRoot = getPrincipalRoot(principalName);
+        if (principalRoot == null) {
+            return;
+        }
+        String name = PermissionUtil.getEntryName(path);
+        if (principalRoot.hasChild(name)) {
+            Tree child = principalRoot.getChild(name);
+            if (PermissionUtil.checkACLPath(child, path)) {
+                loadPermissionEntries(path, entries, child, restrictionProvider);
+            } else {
+                // check for child node
+                for (Tree node : child.getChildren()) {
+                    if (PermissionUtil.checkACLPath(node, path)) {
+                        loadPermissionEntries(path, entries, node, restrictionProvider);
+                    }
+                }
+            }
+        }
+    }
+
+    @Override
+    public void load(@Nonnull Map<String, Collection<PermissionEntry>> entries, @Nonnull String principalName) {
+        Tree principalRoot = getPrincipalRoot(principalName);
+        if (principalRoot != null) {
+            for (Tree entryTree : principalRoot.getChildren()) {
+                loadPermissionEntries(entryTree, entries, restrictionProvider);
+            }
+        }
+    }
+
+    @Override
+    public boolean hasPermissionEntries(@Nonnull String principalName) {
+        return getPrincipalRoot(principalName) != null;
+    }
+
+    @Override
+    public long getNumEntries(@Nonnull String principalName) {
+        Tree tree = getPrincipalRoot(principalName);
+        return tree == null ? 0 : PermissionUtil.getNumPermissions(tree);
+    }
+
+    @Override
+    public long getTimestamp(@Nonnull String principalName) {
+        Tree principalRoot = getPrincipalRoot(principalName);
+        if (principalRoot != null) {
+            PropertyState ps = principalRoot.getProperty(PermissionConstants.REP_TIMESTAMP);
+            if (ps != null) {
+                return ps.getValue(Type.LONG);
+            }
+        }
+        return 0;
+    }
+
+    @Override
+    @Nonnull
+    public PrincipalPermissionEntries load(@Nonnull String principalName) {
+        PrincipalPermissionEntries ret = new PrincipalPermissionEntries(principalName);
+        Tree principalRoot = getPrincipalRoot(principalName);
+        if (principalRoot != null) {
+            for (Tree entryTree : principalRoot.getChildren()) {
+                loadPermissionEntries(entryTree, ret.getEntries(), restrictionProvider);
+            }
+            PropertyState ps = principalRoot.getProperty(PermissionConstants.REP_TIMESTAMP);
+            ret.setTimestamp(ps == null ? System.currentTimeMillis() : ps.getValue(Type.LONG));
+        }
+        return ret;
+    }
+
+    private static void loadPermissionEntries(@Nonnull Tree tree,
+                                              @Nonnull Map<String, Collection<PermissionEntry>> pathEntryMap,
+                                              @Nonnull RestrictionProvider restrictionProvider) {
+        String path = TreeUtil.getString(tree, PermissionConstants.REP_ACCESS_CONTROLLED_PATH);
+        Collection<PermissionEntry> entries = pathEntryMap.get(path);
+        if (entries == null) {
+            entries = new TreeSet<PermissionEntry>();
+            pathEntryMap.put(path, entries);
+        }
+        for (Tree child : tree.getChildren()) {
+            if (child.getName().charAt(0) == 'c') {
+                loadPermissionEntries(child, pathEntryMap, restrictionProvider);
+            } else {
+                entries.add(new PermissionEntry(path, child, restrictionProvider));
+            }
+        }
+    }
+
+    private static void loadPermissionEntries(@Nonnull String path,
+                                              @Nonnull Collection<PermissionEntry> ret,
+                                              @Nonnull Tree tree,
+                                              @Nonnull RestrictionProvider restrictionProvider) {
+        for (Tree ace : tree.getChildren()) {
+            if (ace.getName().charAt(0) != 'c') {
+                ret.add(new PermissionEntry(path, ace, restrictionProvider));
+            }
+        }
+    }
+}
\ No newline at end of file

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionUtil.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionUtil.java?rev=1537792&r1=1537791&r2=1537792&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionUtil.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionUtil.java Fri Nov  1 00:59:06 2013
@@ -22,6 +22,7 @@ import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
 import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Root;
 import org.apache.jackrabbit.oak.api.Tree;
 import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.commons.PathUtils;
@@ -86,13 +87,13 @@ public final class PermissionUtil implem
     }
 
     @Nonnull
-    public static ImmutableTree getPermissionsRoot(ImmutableRoot immutableRoot, String workspaceName) {
-        return immutableRoot.getTree(PERMISSIONS_STORE_PATH + '/' + workspaceName);
+    public static Tree getPermissionsRoot(Root root, String workspaceName) {
+        return root.getTree(PERMISSIONS_STORE_PATH + '/' + workspaceName);
     }
 
     @Nonnull
-    public static Tree getPrincipalRoot(Tree permissionsTree, Principal principal) {
-        return permissionsTree.getChild(Text.escapeIllegalJcrChars(principal.getName()));
+    public static Tree getPrincipalRoot(Tree permissionsTree, String principalName) {
+        return permissionsTree.getChild(Text.escapeIllegalJcrChars(principalName));
     }
 
     public static int getType(@Nonnull ImmutableTree tree, @Nullable PropertyState property) {

Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PrincipalPermissionEntries.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PrincipalPermissionEntries.java?rev=1537792&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PrincipalPermissionEntries.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PrincipalPermissionEntries.java Fri Nov  1 00:59:06 2013
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.security.authorization.permission;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Map;
+
+import javax.annotation.Nonnull;
+
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionConstants;
+import org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionProvider;
+import org.apache.jackrabbit.oak.util.TreeUtil;
+
+/**
+ * <code>PermissionEntries</code> holds the permission entries of one principal
+ */
+public class PrincipalPermissionEntries {
+
+    /**
+     * principal name
+     */
+    private final String name;
+
+    /**
+     * timestamp of the per-principal permission store
+     */
+    private long timestamp;
+
+    /**
+     * map of permission entries, accessed by path
+     */
+    private Map<String, Collection<PermissionEntry>> entries = new HashMap<String, Collection<PermissionEntry>>();
+
+    public PrincipalPermissionEntries(@Nonnull String name) {
+        this.name = name;
+    }
+
+    @Nonnull
+    public String getName() {
+        return name;
+    }
+
+    public long getTimestamp() {
+        return timestamp;
+    }
+
+    public void setTimestamp(long timestamp) {
+        this.timestamp = timestamp;
+    }
+
+    @Nonnull
+    public Collection<PermissionEntry> getEntries(@Nonnull String path) {
+        Collection<PermissionEntry> ret = entries.get(path);
+        return ret == null ? Collections.<PermissionEntry>emptyList() : ret;
+    }
+
+    @Nonnull
+    public Map<String, Collection<PermissionEntry>> getEntries() {
+        return entries;
+    }
+
+}
\ No newline at end of file

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/PermissionConstants.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/PermissionConstants.java?rev=1537792&r1=1537791&r2=1537792&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/PermissionConstants.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/PermissionConstants.java Fri Nov  1 00:59:06 2013
@@ -38,6 +38,7 @@ public interface PermissionConstants {
 
     String REP_ACCESS_CONTROLLED_PATH = "rep:accessControlledPath";
     String REP_NUM_PERMISSIONS = "rep:numPermissions";
+    String REP_TIMESTAMP = "rep:timestamp";
 	String REP_IS_ALLOW = "rep:isAllow";
     String REP_PRIVILEGE_BITS = "rep:privileges";
 

Modified: jackrabbit/oak/trunk/oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/nodetype/write/builtin_nodetypes.cnd
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/nodetype/write/builtin_nodetypes.cnd?rev=1537792&r1=1537791&r2=1537792&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/nodetype/write/builtin_nodetypes.cnd (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/nodetype/write/builtin_nodetypes.cnd Fri Nov  1 00:59:06 2013
@@ -671,6 +671,7 @@
 [rep:PermissionStore]
   - rep:accessControlledPath (STRING) protected
   - rep:numPermissions (LONG) protected
+  - rep:timestamp (LONG) protected
   + * (rep:PermissionStore) = rep:PermissionStore protected IGNORE
   + * (rep:Permissions) = rep:Permissions protected IGNORE
 

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/evaluation/AbstractOakCoreTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/evaluation/AbstractOakCoreTest.java?rev=1537792&r1=1537791&r2=1537792&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/evaluation/AbstractOakCoreTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/evaluation/AbstractOakCoreTest.java Fri Nov  1 00:59:06 2013
@@ -20,6 +20,7 @@ import static com.google.common.base.Pre
 import static org.apache.jackrabbit.JcrConstants.NT_UNSTRUCTURED;
 
 import java.security.Principal;
+import java.util.UUID;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
@@ -116,11 +117,27 @@ public abstract class AbstractOakCoreTes
                                    @Nonnull Principal principal,
                                    boolean isAllow,
                                    @Nonnull String... privilegeNames) throws Exception {
+        setupPermission(root, path, principal, isAllow, privilegeNames);
+    }
+
+    /**
+     * Setup simple allow/deny permissions (without restrictions).
+     *
+     * @param path
+     * @param principal
+     * @param isAllow
+     * @param privilegeNames
+     * @throws Exception
+     */
+    protected void setupPermission(@Nonnull Root root,
+                                   @Nullable String path,
+                                   @Nonnull Principal principal,
+                                   boolean isAllow,
+                                   @Nonnull String... privilegeNames) throws Exception {
     	AccessControlManager acMgr = getAccessControlManager(root);
     	JackrabbitAccessControlList acl = checkNotNull(AccessControlUtils.getAccessControlList(acMgr, path));
       	acl.addEntry(principal, AccessControlUtils.privilegesFromNames(acMgr, privilegeNames), isAllow);
      	acMgr.setPolicy(path, acl);
-
         root.commit();
     }
 }
\ No newline at end of file

Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/evaluation/MultipleSessionsACLStabilityTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/evaluation/MultipleSessionsACLStabilityTest.java?rev=1537792&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/evaluation/MultipleSessionsACLStabilityTest.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/evaluation/MultipleSessionsACLStabilityTest.java Fri Nov  1 00:59:06 2013
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.security.authorization.evaluation;
+
+import java.security.Principal;
+import java.util.List;
+import java.util.UUID;
+
+import javax.jcr.SimpleCredentials;
+import javax.jcr.security.AccessControlManager;
+
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
+import org.apache.jackrabbit.commons.jackrabbit.authorization.AccessControlUtils;
+import org.apache.jackrabbit.oak.api.ContentSession;
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Root;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.AccessControlConstants;
+import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableList;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests if ACL changes done by different sessions are isolated correctly following the MVCC pattern.
+ */
+public class MultipleSessionsACLStabilityTest extends AbstractOakCoreTest {
+
+    private Root testRoot1;
+
+    private Root testRoot2;
+
+    private ContentSession testSession1;
+
+    private ContentSession testSession2;
+
+    @Before
+    public void before() throws Exception {
+        super.before();
+
+        testSession1 = getTestSession();
+        String uid = testPrincipal.getName();
+        testSession2 = login(new SimpleCredentials(uid, uid.toCharArray()));
+
+        setupPermission("/", testPrincipal, true, PrivilegeConstants.JCR_ALL);
+        setupPermission("/a/bb", testPrincipal, false, PrivilegeConstants.JCR_READ);
+
+        testRoot1 = getTestRoot();
+        testRoot2 = testSession2.getLatestRoot();
+    }
+
+
+    @Test
+    public void testAllowChild() throws Exception {
+        Tree rootTree1 = testRoot1.getTree("/");
+        Tree rootTree2 = testRoot2.getTree("/");
+
+        assertFalse(rootTree1.hasChild("a/bb"));
+        assertFalse(rootTree2.hasChild("a/bb"));
+
+        // now allow read with root session
+        setupPermission("/a/bb", testPrincipal, true, PrivilegeConstants.JCR_READ);
+
+        // the test sessions still need to see the old ACLs
+        assertFalse(rootTree1.hasChild("a/bb"));
+        assertFalse(rootTree2.hasChild("a/bb"));
+    }
+
+    @Test
+    public void testAllowChild2() throws Exception {
+        // same as above, but before reading the items
+        setupPermission("/a/bb", testPrincipal, true, PrivilegeConstants.JCR_READ);
+
+        Tree rootTree1 = testRoot1.getTree("/");
+        Tree rootTree2 = testRoot2.getTree("/");
+
+        assertFalse(rootTree1.hasChild("a/bb"));
+        assertFalse(rootTree2.hasChild("a/bb"));
+    }
+
+    @Test
+    public void testAllowChild3() throws Exception {
+        Tree rootTree1 = testRoot1.getTree("/");
+        Tree rootTree2 = testRoot2.getTree("/");
+
+        assertTrue(rootTree1.hasChild("a"));
+        assertTrue(rootTree2.hasChild("a"));
+        assertFalse(rootTree1.hasChild("a/bb"));
+        assertFalse(rootTree2.hasChild("a/bb"));
+
+        setupPermission(testRoot1, "/a", testPrincipal, false, PrivilegeConstants.JCR_READ);
+
+        assertFalse(rootTree1.hasChild("a"));
+        assertTrue(rootTree2.hasChild("a"));
+
+        String uid = testPrincipal.getName();
+        ContentSession session3 = login(new SimpleCredentials(uid, uid.toCharArray()));
+        Tree rootTree3 = session3.getLatestRoot().getTree("/");
+        assertFalse(rootTree3.hasChild("a"));
+
+    }
+}

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionProviderImplTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionProviderImplTest.java?rev=1537792&r1=1537791&r2=1537792&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionProviderImplTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionProviderImplTest.java Fri Nov  1 00:59:06 2013
@@ -102,7 +102,7 @@ public class PermissionProviderImplTest 
     }
 
     private PermissionProvider createPermissionProvider(ContentSession session) {
-        return new PermissionProviderImpl(session.getLatestRoot(), session.getAuthInfo().getPrincipals(), config);
+        return config.getPermissionProvider(session.getLatestRoot(), session.getAuthInfo().getPrincipals());
     }
 
     @Test

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStoreTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStoreTest.java?rev=1537792&r1=1537791&r2=1537792&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStoreTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStoreTest.java Fri Nov  1 00:59:06 2013
@@ -87,8 +87,8 @@ public class PermissionStoreTest extends
         }
     }
 
-    private PermissionProviderImpl createPermissionProvider() {
-        return new PermissionProviderImpl(testRoot, testSession.getAuthInfo().getPrincipals(), acConfig);
+    private PermissionProvider createPermissionProvider() {
+        return acConfig.getPermissionProvider(testRoot, testSession.getAuthInfo().getPrincipals());
     }
 
     @Test

Modified: jackrabbit/oak/trunk/oak-run/run_concurrent.sh
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/run_concurrent.sh?rev=1537792&r1=1537791&r2=1537792&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-run/run_concurrent.sh (original)
+++ jackrabbit/oak/trunk/oak-run/run_concurrent.sh Fri Nov  1 00:59:06 2013
@@ -16,19 +16,21 @@
 # limitations under the License.
 #
 USERS="false true"
-RUNTIME=5
+RUNTIME=10
 #BENCH=ConcurrentReadAccessControlledTreeTest
 BENCH=ManyUserReadTest
 RANDOM_USER="true"
 FIXS="Oak-Tar Jackrabbit"
 THREADS="1,2,4,8,10,15,20,50"
 PROFILE=false
+NUM_ITEMS=10000
 
 LOG=$BENCH"_$(date +'%Y%m%d_%H%M%S').csv"
 echo "Benchmarks: $BENCH" > $LOG
 echo "Fixtures: $FIXS" >> $LOG
 echo "Users: $USERS" >> $LOG
 echo "Runtime: $RUNTIME" >> $LOG
+echo "Num Items: $NUM_ITEMS" >> $LOG
 echo "Concurrency: $THREADS" >> $LOG
 echo "Random User: $RANDOM_USER" >> $LOG
 echo "Profiling: $PROFILE" >> $LOG
@@ -41,7 +43,7 @@ for user in $USERS
         echo "Executing benchmarks as admin: $user on $fix" | tee -a $LOG
 	echo "-----------------------------------------------------------" | tee -a $LOG
         rm -rf target/Jackrabbit-* target/Oak-Tar-*
-        cmd="java -Xmx2048m -Dprofile=$PROFILE -Druntime=$RUNTIME -jar target/oak-run-*-SNAPSHOT.jar benchmark --csvFile $LOG --concurrency $THREADS --runAsAdmin $user --report false --randomUser $RANDOM_USER $BENCH $fix"
+        cmd="java -Xmx2048m -Dprofile=$PROFILE -Druntime=$RUNTIME -Dwarmup=20 -jar target/oak-run-*-SNAPSHOT.jar benchmark --itemsToRead $NUM_ITEMS --csvFile $LOG --concurrency $THREADS --runAsAdmin $user --report false --randomUser $RANDOM_USER $BENCH $fix"
         echo $cmd
         $cmd 
     done



Mime
View raw message