Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/CachingEntryCollector.java
===================================================================
--- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/CachingEntryCollector.java	(revision 1365550)
+++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/CachingEntryCollector.java	(revision )
@@ -24,6 +24,7 @@
 
 import org.apache.jackrabbit.core.NodeImpl;
 import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.core.SessionPoolFactory;
 import org.apache.jackrabbit.core.cache.GrowingLRUMap;
 import org.apache.jackrabbit.core.id.NodeId;
 import org.apache.jackrabbit.core.security.authorization.AccessControlModifications;
@@ -60,7 +61,19 @@
      * @throws RepositoryException If an error occurs.
      */
     CachingEntryCollector(SessionImpl systemSession, NodeId rootID) throws RepositoryException {
-        super(systemSession, rootID);
+        this(systemSession, rootID, null);
+    }
+
+    /**
+     * Create a new instance.
+     *
+     * @param systemSession A system session.
+     * @param rootID The id of the root node.
+     * @param sessionPool A pool of system sessions or {@code null}.
+     * @throws RepositoryException If an error occurs.
+     */
+    CachingEntryCollector(SessionImpl systemSession, NodeId rootID, SessionPoolFactory.Pool sessionPool) throws RepositoryException {
+        super(systemSession, rootID, sessionPool);
         cache = new EntryCache();
 
         // for testing purposes, see JCR-2950
Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/EntryCollector.java
===================================================================
--- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/EntryCollector.java	(revision 1365550)
+++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/EntryCollector.java	(revision )
@@ -18,6 +18,7 @@
 
 import org.apache.jackrabbit.core.NodeImpl;
 import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.core.SessionPoolFactory;
 import org.apache.jackrabbit.core.id.NodeId;
 import org.apache.jackrabbit.core.observation.SynchronousEventListener;
 import org.apache.jackrabbit.core.security.authorization.AccessControlConstants;
@@ -67,6 +68,8 @@
      */
     protected final NodeId rootID;
 
+    private final SessionPoolFactory.Pool sessionPool;
+
     private final EventListener moveListener;
 
     /**
@@ -76,8 +79,20 @@
      * @throws RepositoryException
      */
     protected EntryCollector(SessionImpl systemSession, NodeId rootID) throws RepositoryException {
+        this(systemSession, rootID, null);
+    }
+
+    /**
+     *
+     * @param systemSession
+     * @param rootID
+     * @param sessionPool
+     * @throws RepositoryException
+     */
+    protected EntryCollector(SessionImpl systemSession, NodeId rootID, SessionPoolFactory.Pool sessionPool) throws RepositoryException {
         this.systemSession = systemSession;
         this.rootID = rootID;
+        this.sessionPool = sessionPool;
 
         ObservationManager observationMgr = systemSession.getWorkspace().getObservationManager();
         /*
@@ -215,8 +230,14 @@
      * @throws javax.jcr.RepositoryException
      */
     NodeImpl getNodeById(NodeId nodeId) throws RepositoryException {
-        return ((NodeImpl) systemSession.getItemManager().getItem(nodeId));
+        SessionImpl s;
+        if (sessionPool != null) {
+            s = sessionPool.getSession();
+        } else {
+            s = systemSession;
-    }
+        }
+        return ((NodeImpl) s.getItemManager().getItem(nodeId));
+    }
 
     //------------------------------------------------------< EventListener >---
     /**
Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/CompiledPermissionsImpl.java
===================================================================
--- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/CompiledPermissionsImpl.java	(revision 1365550)
+++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/CompiledPermissionsImpl.java	(revision )
@@ -17,6 +17,7 @@
 package org.apache.jackrabbit.core.security.authorization.acl;
 
 import org.apache.jackrabbit.api.JackrabbitWorkspace;
+import org.apache.jackrabbit.core.SessionPoolFactory;
 import org.apache.jackrabbit.core.cache.GrowingLRUMap;
 import org.apache.jackrabbit.core.ItemImpl;
 import org.apache.jackrabbit.core.ItemManager;
@@ -54,6 +55,7 @@
 
     private final List<String> principalNames;
     private final SessionImpl session;
+    private final SessionPoolFactory.Pool sessionPool;
     private final EntryCollector entryCollector;
     private final AccessControlUtils util;
 
@@ -67,9 +69,11 @@
     private final Object monitor = new Object();
 
     CompiledPermissionsImpl(Set<Principal> principals, SessionImpl session,
+                            SessionPoolFactory.Pool sessionPool,
                             EntryCollector entryCollector, AccessControlUtils util,
                             boolean listenToEvents) throws RepositoryException {
         this.session = session;
+        this.sessionPool = sessionPool;
         this.entryCollector = entryCollector;
         this.util = util;
 
@@ -154,7 +158,8 @@
         boolean existingNode = false;
         NodeImpl node;
 
-        ItemManager itemMgr = session.getItemManager();
+        SessionImpl s = getSession();
+        ItemManager itemMgr = s.getItemManager();
         try {
             ItemImpl item = itemMgr.getItem(absPath);
             if (item.isNode()) {
@@ -167,7 +172,7 @@
             // path points to a non-persisted item.
             // -> find the nearest persisted node starting from the root.
             Path.Element[] elems = absPath.getElements();
-            NodeImpl parent = (NodeImpl) session.getRootNode();
+            NodeImpl parent = (NodeImpl) s.getRootNode();
             for (int i = 1; i < elems.length - 1; i++) {
                 Name name = elems[i].getName();
                 int index = elems[i].getIndex();
@@ -187,7 +192,7 @@
         }
 
         boolean isAcItem = util.isAcItem(absPath);
-        return buildResult(node, existingNode, isAcItem, new EntryFilterImpl(principalNames, absPath, session));
+        return buildResult(node, existingNode, isAcItem, new EntryFilterImpl(principalNames, absPath, s));
     }
 
     @Override
@@ -275,6 +280,14 @@
         return canRead;
     }
 
+    private SessionImpl getSession() {
+        if (sessionPool != null) {
+            return sessionPool.getSession();
+        } else {
+            return session;
+        }
+    }
+
     //----------------------------------------< ACLModificationListener >---
     /**
      * @see org.apache.jackrabbit.core.security.authorization.AccessControlListener#acModified(org.apache.jackrabbit.core.security.authorization.AccessControlModifications)
Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionPoolFactory.java
===================================================================
--- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionPoolFactory.java	(revision )
+++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionPoolFactory.java	(revision )
@@ -0,0 +1,108 @@
+/*
+ * 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.core;
+
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+
+/**
+ * Factory used to create a pool of {@code SystemSession} instances.
+ */
+public class SessionPoolFactory {
+
+    SessionPoolFactory() {}
+
+    public Pool createPool() {
+        return new Pool();
+    }
+
+    public class Pool {
+
+        boolean initialized;
+        SessionImpl[] sessions;
+        volatile int sindex = 0;
+
+        // private constructor
+        private Pool() {}
+
+        /**
+         * Initializes this instance of a system session pool using the specified
+         * {@code session} and the given {@code size}. The init creates new
+         * instances of SystemSession will be created and the specified session
+         * will not be held in the pool.
+         *
+         * @param session Session used to initialize the pool.
+         * @param size The desired number of system sessions to held in the pool.
+         * @throws IllegalStateException If this pool has been initialized before
+         * @throws IllegalArgumentException If the pool size is &lt;1
+         * @throws RepositoryException If an error occurs.
+         */
+        public void init(SessionImpl session, int size) throws RepositoryException {
+            if (initialized) {
+                throw new IllegalStateException("Already initialized");
+            }
+            if (size < 1) {
+                throw new IllegalArgumentException("Invalid pool size " + size);
+            }
+
+            String workspaceName = session.getWorkspace().getName();
+            Repository repository = session.getRepository();
+            if (!(repository instanceof RepositoryImpl)) {
+                throw new IllegalArgumentException("Invalid repository implementation.");
+            }
+            RepositoryImpl repoImpl = (RepositoryImpl) repository;
+            sessions = new SessionImpl[size];
+            for (int i = 0; i < size; i++) {
+                sessions[i] = SystemSession.create(repoImpl.getRepositoryContext(), repoImpl.getConfig().getWorkspaceConfig(workspaceName));
+            }
+
+            initialized = true;
+        }
+
+        /**
+         * Disposes this pools and calls {@link javax.jcr.Session#logout()} on
+         * all session held by it.
+         */
+        public void dispose() {
+            checkInitialized();
+            for (SessionImpl s : sessions) {
+                if (s.isLive()) {
+                    s.logout();
+                }
+            }
+            initialized = false;
+            sessions = null;
+        }
+
+        /**
+         * Returns a session out of the session pool.
+         *
+         * @return a session out of the pool.
+         */
+        public SessionImpl getSession() {
+            checkInitialized();
+            int n = (sindex++) % sessions.length;
+            return sessions[n];
+        }
+
+        private void checkInitialized() {
+            if (!initialized) {
+                throw new IllegalStateException("Not yet initialized");
+            }
+        }
+    }
+}
\ No newline at end of file
Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AccessControlProviderFactoryImpl.java
===================================================================
--- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AccessControlProviderFactoryImpl.java	(revision 1365550)
+++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AccessControlProviderFactoryImpl.java	(revision )
@@ -16,6 +16,7 @@
  */
 package org.apache.jackrabbit.core.security.authorization;
 
+import org.apache.jackrabbit.core.SessionPoolFactory;
 import org.apache.jackrabbit.core.config.BeanConfig;
 import org.apache.jackrabbit.core.config.WorkspaceSecurityConfig;
 import org.apache.jackrabbit.core.security.authorization.acl.ACLProvider;
@@ -40,12 +41,21 @@
      */
     private static final Logger log = LoggerFactory.getLogger(AccessControlProviderFactoryImpl.class);
 
+    private final SessionPoolFactory sessionPoolFactory;
+
     /**
      * The name of the security workspace (containing users...)
      */
     private String secWorkspaceName;
     private String defaultWorkspaceName;
 
+    public AccessControlProviderFactoryImpl() {
+        this(null);
+    }
+
+    public AccessControlProviderFactoryImpl(SessionPoolFactory sessionPool) {
+        this.sessionPoolFactory = sessionPool;
+    }
     //---------------------------------------< AccessControlProviderFactory >---
     /**
      * @see AccessControlProviderFactory#init(Session)
@@ -76,6 +86,13 @@
             BeanConfig bc = config.getAccessControlProviderConfig();
             prov = bc.newInstance(AccessControlProvider.class);
             props = bc.getParameters();
+
+            // create a new session pool for the ac provider if the factory is
+            // present and the access control provider configuration contains
+            // the config option "session-pool".
+            if (sessionPoolFactory != null && Boolean.parseBoolean(bc.getParameters().getProperty(AbstractAccessControlProvider.PARAM_SESSION_POOL, "false"))) {
+                props.put(AbstractAccessControlProvider.PARAM_SESSION_POOL, sessionPoolFactory.createPool());
+            }
         } else {
             log.debug("No ac-provider configuration for workspace " + workspaceName + " -> using defaults.");
             if (workspaceName.equals(secWorkspaceName) && !workspaceName.equals(defaultWorkspaceName)) {
Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/DefaultSecurityManager.java
===================================================================
--- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/DefaultSecurityManager.java	(revision 1365550)
+++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/DefaultSecurityManager.java	(revision )
@@ -204,7 +204,7 @@
         createSystemUsers(systemUserManager, this.systemSession, adminId, anonymousId);
 
         // init default ac-provider-factory
-        acProviderFactory = new AccessControlProviderFactoryImpl();
+        acProviderFactory = new AccessControlProviderFactoryImpl(new SessionPoolFactory());
         acProviderFactory.init(this.systemSession);
 
         // create the workspace access manager
@@ -579,14 +579,12 @@
             repository.markWorkspaceActive(workspaceName);
 
             WorkspaceSecurityConfig secConf = null;
-            WorkspaceConfig conf =
-                repository.getConfig().getWorkspaceConfig(workspaceName);
+            WorkspaceConfig conf = repository.getConfig().getWorkspaceConfig(workspaceName);
             if (conf != null) {
                 secConf = conf.getSecurityConfig();
             }
 
-            provider = acProviderFactory.createProvider(
-                    repository.getSystemSession(workspaceName), secConf);
+            provider = acProviderFactory.createProvider(repository.getSystemSession(workspaceName), secConf);
             synchronized (acProviders) {
                 acProviders.put(workspaceName, provider);
             }
Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AbstractAccessControlProvider.java
===================================================================
--- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AbstractAccessControlProvider.java	(revision 1365550)
+++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AbstractAccessControlProvider.java	(revision )
@@ -56,6 +56,14 @@
     public static final String PARAM_OMIT_DEFAULT_PERMISSIONS = "omit-default-permission";
 
     /**
+     * Constant for the name of the configuration option "session-pool". The
+     * option is intended to be a flag indicating if a session pool
+     * should be created for the configured access control provider. If the
+     * config option is missing no session pool will be created (default).
+     */
+    public static final String PARAM_SESSION_POOL = "session-pool";
+
+    /**
      * the system session this provider has been created for.
      */
     protected SessionImpl session;
Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLProvider.java
===================================================================
--- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLProvider.java	(revision 1365550)
+++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLProvider.java	(revision )
@@ -19,6 +19,7 @@
 import org.apache.jackrabbit.api.security.principal.PrincipalManager;
 import org.apache.jackrabbit.core.NodeImpl;
 import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.core.SessionPoolFactory;
 import org.apache.jackrabbit.core.id.NodeId;
 import org.apache.jackrabbit.core.nodetype.NodeTypeImpl;
 import org.apache.jackrabbit.core.security.SecurityConstants;
@@ -96,6 +97,11 @@
      */
     private EntryCollector entryCollector;
 
+    /**
+     * Session pool containing multiple system session (see JCR-3394)
+     */
+    private SessionPoolFactory.Pool sessionPool;
+
     //----------------------------------------------< AccessControlProvider >---
     /**
      * @see org.apache.jackrabbit.core.security.authorization.AccessControlProvider#init(Session, Map)
@@ -116,6 +122,13 @@
             initRootACL(session, systemEditor);
         }
 
+        if (configuration.containsKey(PARAM_SESSION_POOL)) {
+            sessionPool = (SessionPoolFactory.Pool) configuration.get(PARAM_SESSION_POOL);
+            String propname = "org.apache.jackrabbit.core.security.authorization.acl.ACLProvider.sessionpoolsize";
+            int size = Integer.parseInt(System.getProperty(propname, "8"));
+            sessionPool.init(session, size);
+        }
+
         entryCollector = createEntryCollector(session);
     }
 
@@ -123,7 +136,10 @@
     public void close() {
         super.close();        
         entryCollector.close();
+        if (sessionPool != null) {
+            sessionPool.dispose();
-    }
+        }
+    }
 
     /**
      * @see org.apache.jackrabbit.core.security.authorization.AccessControlProvider#getEffectivePolicies(org.apache.jackrabbit.spi.Path,org.apache.jackrabbit.core.security.authorization.CompiledPermissions)
@@ -240,7 +256,7 @@
         } else if (isReadOnly(principals)) {
             return getReadOnlyPermissions();
         } else {
-            return new CompiledPermissionsImpl(principals, session, entryCollector, this, true);
+            return new CompiledPermissionsImpl(principals, session, sessionPool, entryCollector, this, true);
         }
     }
 
@@ -252,7 +268,7 @@
         if (isAdminOrSystem(principals)) {
             return true;
         } else {
-            CompiledPermissions cp = new CompiledPermissionsImpl(principals, session, entryCollector, this, false);
+            CompiledPermissions cp = new CompiledPermissionsImpl(principals, session, sessionPool, entryCollector, this, false);
             try {
                 return cp.canRead(null, rootNodeId);
             } finally {
@@ -272,7 +288,7 @@
      * @throws RepositoryException If an error occurs.
      */
     protected EntryCollector createEntryCollector(SessionImpl systemSession) throws RepositoryException {
-        return new CachingEntryCollector(systemSession, rootNodeId);
+        return new CachingEntryCollector(systemSession, rootNodeId, sessionPool);
     }
 
     //------------------------------------------------------------< private >---
