jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From dpfis...@apache.org
Subject svn commit: r546038 - in /jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core: cluster/ lock/
Date Mon, 11 Jun 2007 08:10:13 GMT
Author: dpfister
Date: Mon Jun 11 01:10:12 2007
New Revision: 546038

URL: http://svn.apache.org/viewvc?view=rev&rev=546038
Log:
JCR-929: Under Heavy load in a Cluster HTTP Threads Block and stall requests

Added:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/AbstractClusterOperation.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/ClusterOperation.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/LockOperation.java
Modified:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/ClusterNode.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/LockEventChannel.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/UpdateEventChannel.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/LockManagerImpl.java

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/AbstractClusterOperation.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/AbstractClusterOperation.java?view=auto&rev=546038
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/AbstractClusterOperation.java
(added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/AbstractClusterOperation.java
Mon Jun 11 01:10:12 2007
@@ -0,0 +1,88 @@
+/*
+ * 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.cluster;
+
+import org.apache.jackrabbit.core.journal.JournalException;
+import org.apache.jackrabbit.core.journal.Record;
+
+/**
+ * Base implementation of a cluster operation that contains common funtionality
+ * that should not be directly exposed in the {@link ClusterOperation} interface.
+ */
+abstract class AbstractClusterOperation implements ClusterOperation {
+
+    /**
+     * Cluster node.
+     */
+    private ClusterNode clusterNode;
+
+    /**
+     * Workspace where operation takes place.
+     */
+    protected String workspace;
+
+    /**
+     * Journal record associated with this operation.
+     */
+    protected Record record;
+
+    /**
+     * Create a new instance of this class.
+     *
+     * @param clusterNode cluster node
+     * @param workspace workspace where operation takes place.
+     * @param record journal record
+     */
+    public AbstractClusterOperation(ClusterNode clusterNode, String workspace,
+                                    Record record) {
+        this.clusterNode = clusterNode;
+        this.workspace = workspace;
+        this.record = record;
+    }
+
+    /**
+     * Return the workspace where this operation takes place.
+     *
+     * @return workspace
+     */
+    public String getWorkspace() {
+        return workspace;
+    }
+
+    /**
+     * Return the record used to serialize/deserialize this operation.
+     *
+     * @return record
+     */
+    public Record getRecord() {
+        return record;
+    }
+
+    /**
+     * Serialize this operation to the record. Subclass responsibility.
+     *
+     * @throws JournalException if an error occurs
+     */
+    protected abstract void write() throws JournalException;
+    
+    /**
+     * {@inheritDoc}
+     */
+    public void ended(boolean successful) {
+        clusterNode.ended(this, successful);
+    }
+}

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/ClusterNode.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/ClusterNode.java?view=diff&rev=546038&r1=546037&r2=546038
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/ClusterNode.java
(original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/ClusterNode.java
Mon Jun 11 01:10:12 2007
@@ -677,64 +677,46 @@
         /**
          * {@inheritDoc}
          */
-        public void locked(NodeId nodeId, boolean deep, String owner) {
+        public ClusterOperation create(NodeId nodeId, boolean deep, String owner) {
             if (status != STARTED) {
                 log.info("not started: lock operation ignored.");
-                return;
+                return null;
             }
-            Record record = null;
-            boolean succeeded = false;
-
             try {
-                record = journal.getProducer(PRODUCER_ID).append();
-                record.writeString(workspace);
-                write(record, nodeId, deep, owner);
-                record.writeChar('\0');
-                record.update();
-                setRevision(record.getRevision());
-                succeeded = true;
+                Record record = journal.getProducer(PRODUCER_ID).append();
+                return new LockOperation(ClusterNode.this, workspace, record,
+                        nodeId, deep, owner);
             } catch (JournalException e) {
                 String msg = "Unable to create log entry: " + e.getMessage();
                 log.error(msg);
+                return null;
             } catch (Throwable e) {
                 String msg = "Unexpected error while creating log entry.";
                 log.error(msg, e);
-            } finally {
-                if (!succeeded && record != null) {
-                    record.cancelUpdate();
-                }
+                return null;
             }
         }
 
         /**
          * {@inheritDoc}
          */
-        public void unlocked(NodeId nodeId) {
+        public ClusterOperation create(NodeId nodeId) {
             if (status != STARTED) {
                 log.info("not started: unlock operation ignored.");
-                return;
+                return null;
             }
-            Record record = null;
-            boolean succeeded = false;
-
             try {
-                record = journal.getProducer(PRODUCER_ID).append();
-                record.writeString(workspace);
-                write(record, nodeId);
-                record.writeChar('\0');
-                record.update();
-                setRevision(record.getRevision());
-                succeeded = true;
+                Record record = journal.getProducer(PRODUCER_ID).append();
+                return new LockOperation(ClusterNode.this, workspace, record,
+                        nodeId);
             } catch (JournalException e) {
                 String msg = "Unable to create log entry: " + e.getMessage();
                 log.error(msg);
+                return null;
             } catch (Throwable e) {
                 String msg = "Unexpected error while creating log entry.";
                 log.error(msg, e);
-            } finally {
-                if (!succeeded && record != null) {
-                    record.cancelUpdate();
-                }
+                return null;
             }
         }
 
@@ -1182,18 +1164,6 @@
         record.writeString(uri);
     }
 
-    private static void write(Record record, NodeId nodeId, boolean isDeep, String owner)
-            throws JournalException {
-
-        write(record, nodeId, true, isDeep, owner);
-    }
-
-    private static void write(Record record, NodeId nodeId)
-            throws JournalException {
-
-        write(record, nodeId, false, false, null);
-    }
-
     private static void write(Record record, Collection c, boolean register)
             throws JournalException {
 
@@ -1268,16 +1238,40 @@
         record.writeString(event.getUserId());
     }
 
-    private static void write(Record record, NodeId nodeId, boolean isLock,
-                              boolean isDeep, String owner)
-            throws JournalException {
+    /**
+     * Invoked when a cluster operation has ended. If <code>successful</code>,
+     * attempts to fill the journal record and update it, otherwise cancels
+     * the update.
+     *
+     * @param operation cluster operation
+     * @param successful <code>true</code> if the operation was successful and
+     *                   the journal record should be updated;
+     *                   <code>false</code> to revoke changes
+     */
+    public void ended(AbstractClusterOperation operation, boolean successful) {
+        Record record = operation.getRecord();
+        boolean succeeded = false;
 
-        record.writeChar('L');
-        record.writeNodeId(nodeId);
-        record.writeBoolean(isLock);
-        if (isLock) {
-            record.writeBoolean(isDeep);
-            record.writeString(owner);
+        try {
+            if (successful) {
+                record = operation.getRecord();
+                record.writeString(operation.getWorkspace());
+                operation.write();
+                record.writeChar('\0');
+                record.update();
+                setRevision(record.getRevision());
+                succeeded = true;
+            }
+        } catch (JournalException e) {
+            String msg = "Unable to create log entry: " + e.getMessage();
+            log.error(msg);
+        } catch (Throwable e) {
+            String msg = "Unexpected error while creating log entry.";
+            log.error(msg, e);
+        } finally {
+            if (!succeeded) {
+                record.cancelUpdate();
+            }
         }
     }
 }

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/ClusterOperation.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/ClusterOperation.java?view=auto&rev=546038
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/ClusterOperation.java
(added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/ClusterOperation.java
Mon Jun 11 01:10:12 2007
@@ -0,0 +1,33 @@
+/*
+ * 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.cluster;
+
+/**
+ * Cluster operation that will be written to the cluster's journal and
+ * ultimately processed by other instances.
+ */
+public interface ClusterOperation {
+
+    /**
+     * Called when the operation has been finished. The passed flag indicates
+     * whether or not the operation was successful.
+     *
+     * @param successful <code>true</code> if the operation ended successfully;
+     *                   <code>false</code> otherwise
+     */
+    public void ended(boolean successful);
+}

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/LockEventChannel.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/LockEventChannel.java?view=diff&rev=546038&r1=546037&r2=546038
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/LockEventChannel.java
(original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/LockEventChannel.java
Mon Jun 11 01:10:12 2007
@@ -24,20 +24,27 @@
 public interface LockEventChannel {
 
     /**
-     * Called when a node has been locked.
+     * Create a new cluster operation that should be used to inform other
+     * instances in the cluster. Called when a node is about to be
+     * locked. 
      *
      * @param nodeId node id
      * @param deep flag indicating whether lock is deep
      * @param owner lock owner
+     * @return cluster operation or <code>null</code> if the cluster node
+     *         is not started or some error occurs
      */
-    public void locked(NodeId nodeId, boolean deep, String owner);
+    public ClusterOperation create(NodeId nodeId, boolean deep, String owner);
 
     /**
-     * Called when a node has been unlocked.
+     * Create a new cluster operation  that should be used to inform other
+     * instances in the cluster. Called when a node has been unlocked.
      *
      * @param nodeId node id
+     * @return cluster operation or <code>null</code> if the cluster node
+     *         is not started or some error occurs
      */
-    public void unlocked(NodeId nodeId);
+    public ClusterOperation create(NodeId nodeId);
 
     /**
      * Set listener that will receive information about incoming, external lock events.

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/LockOperation.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/LockOperation.java?view=auto&rev=546038
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/LockOperation.java
(added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/LockOperation.java
Mon Jun 11 01:10:12 2007
@@ -0,0 +1,131 @@
+/*
+ * 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.cluster;
+
+import org.apache.jackrabbit.core.NodeId;
+import org.apache.jackrabbit.core.journal.JournalException;
+import org.apache.jackrabbit.core.journal.Record;
+
+/**
+ * Lock operation.
+ */
+class LockOperation extends AbstractClusterOperation {
+
+    /**
+     * Node that was locked.
+     */
+    private NodeId nodeId;
+
+    /**
+     * Flag indicating whether this is a deep lock.
+     */
+    private boolean deep;
+
+    /**
+     * Lock owner
+     */
+    private String owner;
+
+    /**
+     * Flag indicating whether this is a lock. 
+     */
+    private boolean isLock;
+
+    /**
+     * Create an instance of this class. This operation will represent
+     * a lock.
+     */
+    protected LockOperation(ClusterNode clusterNode, String workspace,
+                            Record record, NodeId nodeId, boolean deep,
+                            String owner) {
+
+        super(clusterNode, workspace, record);
+
+        this.nodeId = nodeId;
+        this.deep = deep;
+        this.owner = owner;
+        isLock = false;
+    }
+
+    /**
+     * Create an instance of this class. Used to represent an unlock
+     * operation.
+     *
+     * @param clusterNode cluster node
+     * @param workspace workspace where operation takes place.
+     * @param nodeId unlocked node's id
+     */
+    protected LockOperation(ClusterNode clusterNode, String workspace,
+                            Record record, NodeId nodeId) {
+
+        super(clusterNode, workspace, record);
+
+        this.nodeId = nodeId;
+        this.isLock = false;
+    }
+
+    /**
+     * Return a flag indicating whether this is a lock.
+     *
+     * @return <code>true</code> if this is a lock;
+     *         <code>false</code> if this is an unlock
+     */
+    public boolean isLock() {
+        return isLock;
+    }
+
+    /**
+     * Return the target of the lock operation.
+     *
+     * @return node id
+     */
+    public NodeId getNodeId() {
+        return nodeId;
+    }
+
+    /**
+     * Return a flag indicating whether the lock is deep.
+     *
+     * @return <code>true</code> if the lock is deep;
+     *         <code>false</code> otherwise
+     */
+    public boolean isDeep() {
+        return deep;
+    }
+
+    /**
+     * Return the lock's owner.
+     *
+     * @return lock's owner
+     */
+    public String getOwner() {
+        return owner;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void write() throws JournalException {
+        record.writeChar('L');
+        record.writeNodeId(nodeId);
+        record.writeBoolean(isLock);
+        if (isLock) {
+            record.writeBoolean(deep);
+            record.writeString(owner);
+        }
+    }
+}

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/UpdateEventChannel.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/UpdateEventChannel.java?view=diff&rev=546038&r1=546037&r2=546038
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/UpdateEventChannel.java
(original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/UpdateEventChannel.java
Mon Jun 11 01:10:12 2007
@@ -16,10 +16,6 @@
  */
 package org.apache.jackrabbit.core.cluster;
 
-import org.apache.jackrabbit.core.state.ChangeLog;
-import org.apache.jackrabbit.core.state.SharedItemStateManager;
-import org.apache.jackrabbit.core.observation.EventStateCollection;
-
 /**
  * Event channel used to transmit update operations.
  */

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/LockManagerImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/LockManagerImpl.java?view=diff&rev=546038&r1=546037&r2=546038
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/LockManagerImpl.java
(original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/LockManagerImpl.java
Mon Jun 11 01:10:12 2007
@@ -27,6 +27,7 @@
 import org.apache.jackrabbit.core.util.Dumpable;
 import org.apache.jackrabbit.core.cluster.LockEventChannel;
 import org.apache.jackrabbit.core.cluster.LockEventListener;
+import org.apache.jackrabbit.core.cluster.ClusterOperation;
 import org.apache.jackrabbit.core.fs.FileSystem;
 import org.apache.jackrabbit.core.fs.FileSystemException;
 import org.apache.jackrabbit.core.fs.FileSystemResource;
@@ -261,6 +262,14 @@
         LockInfo info = new LockInfo(new LockToken(node.getNodeId()),
                 isSessionScoped, isDeep, session.getUserID());
 
+        ClusterOperation operation = null;
+        boolean successful = false;
+
+        // Cluster is only informed about open-scoped locks
+        if (eventChannel != null && !isSessionScoped) {
+            operation = eventChannel.create(node.getNodeId(), isDeep, session.getUserID());
+        }
+
         acquire();
 
         try {
@@ -289,15 +298,16 @@
             lockMap.put(path, info);
 
             if (!info.sessionScoped) {
-                if (eventChannel != null) {
-                    eventChannel.locked(node.getNodeId(), isDeep, session.getUserID());
-                }
                 save();
+                successful = true;
             }
             return info;
 
         } finally {
             release();
+            if (operation != null) {
+                operation.ended(successful);
+            }
         }
     }
 
@@ -310,6 +320,13 @@
     void internalUnlock(NodeImpl node)
             throws LockException, RepositoryException {
 
+        ClusterOperation operation = null;
+        boolean successful = false;
+
+        if (eventChannel != null) {
+            operation = eventChannel.create(node.getNodeId());
+        }
+        
         acquire();
 
         try {
@@ -334,14 +351,15 @@
             info.setLive(false);
 
             if (!info.sessionScoped) {
-                if (eventChannel != null) {
-                    eventChannel.unlocked(node.getNodeId());
-                }
                 save();
+                successful = true;
             }
-
         } finally {
             release();
+
+            if (operation != null) {
+                operation.ended(successful);
+            }
         }
     }
 



Mime
View raw message