You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by dp...@apache.org on 2007/05/25 10:41:55 UTC

svn commit: r541585 - in /jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core: cluster/ClusterNode.java cluster/NodeTypeEventChannel.java cluster/NodeTypeEventListener.java nodetype/NodeTypeRegistry.java

Author: dpfister
Date: Fri May 25 01:41:46 2007
New Revision: 541585

URL: http://svn.apache.org/viewvc?view=rev&rev=541585
Log:
JCR-699: Clustering: re-registration of nodetypes is not synchronized

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/NodeTypeEventChannel.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/NodeTypeEventListener.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/NodeTypeRegistry.java

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=541585&r1=541584&r2=541585
==============================================================================
--- 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 Fri May 25 01:41:46 2007
@@ -94,6 +94,26 @@
     private static final int STOPPED = 2;
 
     /**
+     * Bit indicating this is a registration operation.
+     */
+    private static final int NTREG_REGISTER = 0;
+
+    /**
+     * Bit indicating this is a reregistration operation.
+     */
+    private static final int NTREG_REREGISTER = (1 << 30);
+
+    /**
+     * Bit indicating this is an unregistration operation.
+     */
+    private static final int NTREG_UNREGISTER = (1 << 31);
+
+    /**
+     * Mask used in node type registration operations.
+     */
+    private static final int NTREG_MASK = (NTREG_REREGISTER | NTREG_UNREGISTER);
+
+    /**
      * Logger.
      */
     private static Logger log = LoggerFactory.getLogger(ClusterNode.class);
@@ -405,7 +425,71 @@
         try {
             record = journal.getProducer(PRODUCER_ID).append();
             record.writeString(null);
-            write(record, ntDefs);
+            write(record, ntDefs, true);
+            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 != null) {
+                record.cancelUpdate();
+            }
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void reregistered(NodeTypeDef ntDef) {
+        if (status != STARTED) {
+            log.info("not started: nodetype operation ignored.");
+            return;
+        }
+        Record record = null;
+        boolean succeeded = false;
+
+        try {
+            record = journal.getProducer(PRODUCER_ID).append();
+            record.writeString(null);
+            write(record, ntDef);
+            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 != null) {
+                record.cancelUpdate();
+            }
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void unregistered(Collection qnames) {
+        if (status != STARTED) {
+            log.info("not started: nodetype operation ignored.");
+            return;
+        }
+        Record record = null;
+        boolean succeeded = false;
+
+        try {
+            record = journal.getProducer(PRODUCER_ID).append();
+            record.writeString(null);
+            write(record, qnames, false);
             record.writeChar('\0');
             record.update();
             setRevision(record.getRevision());
@@ -781,16 +865,46 @@
     /**
      * Process one or more node type registrations.
      *
-     * @param ntDefs node type definition
+     * @param c collection of node type definitions, if this is a register
+     *          operation; collection of <code>QName</code>s if this is
+     *          an unregister operation
+     * @param register <code>true</code>, if this is a register operation;
+     *                 <code>false</code> otherwise
+     */
+    private void process(Collection c, boolean register) {
+        if (nodeTypeListener == null) {
+            String msg = "NodeType listener unavailable.";
+            log.error(msg);
+            return;
+        }
+        try {
+            if (register) {
+                nodeTypeListener.externalRegistered(c);
+            } else {
+                nodeTypeListener.externalUnregistered(c);
+            }
+        } catch (InvalidNodeTypeDefException e) {
+            String msg = "Unable to deliver node type operation: " + e.getMessage();
+            log.error(msg);
+        } catch (RepositoryException e) {
+            String msg = "Unable to deliver node type operation: " + e.getMessage();
+            log.error(msg);
+        }
+    }
+
+    /**
+     * Process a node type re-registration.
+     *
+     * @param ntDef node type definition
      */
-    private void process(Collection ntDefs) {
+    private void process(NodeTypeDef ntDef) {
         if (nodeTypeListener == null) {
             String msg = "NodeType listener unavailable.";
             log.error(msg);
             return;
         }
         try {
-            nodeTypeListener.externalRegistered(ntDefs);
+            nodeTypeListener.externalReregistered(ntDef);
         } catch (InvalidNodeTypeDefException e) {
             String msg = "Unable to deliver node type operation: " + e.getMessage();
             log.error(msg);
@@ -918,11 +1032,30 @@
                     process(oldPrefix, newPrefix, uri);
                 } else if (c == 'T') {
                     int size = record.readInt();
-                    HashSet ntDefs = new HashSet();
-                    for (int i = 0; i < size; i++) {
-                        ntDefs.add(record.readNodeTypeDef());
+                    int opcode = size & NTREG_MASK;
+                    size &= ~NTREG_MASK;
+
+                    switch (opcode) {
+                        case NTREG_REGISTER:
+                            HashSet ntDefs = new HashSet();
+                            for (int i = 0; i < size; i++) {
+                                ntDefs.add(record.readNodeTypeDef());
+                            }
+                            process(ntDefs, true);
+                            break;
+                        case NTREG_REREGISTER:
+                            process(record.readNodeTypeDef());
+                            break;
+                        case NTREG_UNREGISTER:
+                            HashSet ntNames = new HashSet();
+                            for (int i = 0; i < size; i++) {
+                                ntNames.add(record.readQName());
+                            }
+                            process(ntNames, false);
+                            break;
+                        default:
+                            throw new IllegalArgumentException("Unknown opcode: " + opcode);
                     }
-                    process(ntDefs);
                 } else {
                     throw new IllegalArgumentException("Unknown entry type: " + c);
                 }
@@ -1061,16 +1194,37 @@
         write(record, nodeId, false, false, null);
     }
 
-    private static void write(Record record, Collection ntDefs)
+    private static void write(Record record, Collection c, boolean register)
             throws JournalException {
 
         record.writeChar('T');
-        record.writeInt(ntDefs.size());
 
-        Iterator iter = ntDefs.iterator();
+        int size = c.size();
+        if (!register) {
+            size |= NTREG_UNREGISTER;
+        }
+        record.writeInt(size);
+
+        Iterator iter = c.iterator();
         while (iter.hasNext()) {
-            record.writeNodeTypeDef((NodeTypeDef) iter.next());
+            if (register) {
+                record.writeNodeTypeDef((NodeTypeDef) iter.next());
+            } else {
+                record.writeQName((QName) iter.next());
+            }
         }
+    }
+
+    private static void write(Record record, NodeTypeDef ntDef)
+            throws JournalException {
+
+        record.writeChar('T');
+
+        int size = 1;
+        size |= NTREG_REREGISTER;
+        record.writeInt(size);
+
+        record.writeNodeTypeDef(ntDef);
     }
 
     private static void write(Record record, PropertyOperation operation)

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/NodeTypeEventChannel.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/NodeTypeEventChannel.java?view=diff&rev=541585&r1=541584&r2=541585
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/NodeTypeEventChannel.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/NodeTypeEventChannel.java Fri May 25 01:41:46 2007
@@ -16,6 +16,8 @@
  */
 package org.apache.jackrabbit.core.cluster;
 
+import org.apache.jackrabbit.core.nodetype.NodeTypeDef;
+
 import java.util.Collection;
 
 /**
@@ -29,6 +31,20 @@
      * @param ntDefs collection of node type definitions
      */
     public void registered(Collection ntDefs);
+
+    /**
+     * Called when a node types has been re-registered.
+     *
+     * @param ntDef node type definition
+     */
+    public void reregistered(NodeTypeDef ntDef);
+
+    /**
+     * Called when one or more node types have been unregistered.
+     *
+     * @param ntNames collection of node type qnames
+     */
+    public void unregistered(Collection ntNames);
 
     /**
      * Set listener that will receive information about incoming, external node type events.

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/NodeTypeEventListener.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/NodeTypeEventListener.java?view=diff&rev=541585&r1=541584&r2=541585
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/NodeTypeEventListener.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/NodeTypeEventListener.java Fri May 25 01:41:46 2007
@@ -17,8 +17,10 @@
 package org.apache.jackrabbit.core.cluster;
 
 import org.apache.jackrabbit.core.nodetype.InvalidNodeTypeDefException;
+import org.apache.jackrabbit.core.nodetype.NodeTypeDef;
 
 import javax.jcr.RepositoryException;
+import javax.jcr.nodetype.NoSuchNodeTypeException;
 import java.util.Collection;
 
 /**
@@ -35,4 +37,25 @@
      */
     public void externalRegistered(Collection ntDefs)
             throws RepositoryException, InvalidNodeTypeDefException;
+
+    /**
+     * Called when a node type has been externally re-registered.
+     *
+     * @param ntDef node type definition
+     * @throws RepositoryException if an error occurs
+     * @throws NoSuchNodeTypeException if the node type had not yet been registered
+     * @throws InvalidNodeTypeDefException if the node type definition is invalid
+     */
+    public void externalReregistered(NodeTypeDef ntDef)
+        throws NoSuchNodeTypeException, InvalidNodeTypeDefException, RepositoryException;
+
+    /**
+     * Called when one or more node types have been externally unregistered.
+     *
+     * @param ntNames node type qnames
+     * @throws RepositoryException if an error occurs
+     * @throws NoSuchNodeTypeException if a node type is already unregistered
+     */
+    public void externalUnregistered(Collection ntNames)
+        throws RepositoryException, NoSuchNodeTypeException;
 }

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/NodeTypeRegistry.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/NodeTypeRegistry.java?view=diff&rev=541585&r1=541584&r2=541585
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/NodeTypeRegistry.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/NodeTypeRegistry.java Fri May 25 01:41:46 2007
@@ -200,8 +200,23 @@
      * @throws InvalidNodeTypeDefException if the given node type definition is invalid.
      * @throws RepositoryException if a repository error occurs.
      */
-    public synchronized void registerNodeTypes(Collection ntDefs)
+    public void registerNodeTypes(Collection ntDefs)
             throws InvalidNodeTypeDefException, RepositoryException {
+
+        registerNodeTypes(ntDefs, false);
+    }
+
+    /**
+     * Internal implementation of {@link #registerNodeTypes(Collection)}
+     *
+     * @param ntDefs a collection of <code>NodeTypeDef<code> objects
+     * @param external whether this invocation should be considered external
+     * @throws InvalidNodeTypeDefException if the given node type definition is invalid.
+     * @throws RepositoryException if a repository error occurs.
+     */
+    private synchronized void registerNodeTypes(Collection ntDefs, boolean external)
+            throws InvalidNodeTypeDefException, RepositoryException {
+
         // validate and register new node type definitions
         internalRegister(ntDefs);
         // persist new node type definitions
@@ -211,8 +226,8 @@
         }
         persistCustomNodeTypeDefs(customNTDefs);
 
-        // inform cluster
-        if (eventChannel != null) {
+        // inform cluster if this is not an external invocation
+        if (!external && eventChannel != null) {
             eventChannel.registered(ntDefs);
         }
 
@@ -237,8 +252,25 @@
      * @throws RepositoryException if another error occurs
      * @see #unregisterNodeType(QName)
      */
-    public synchronized void unregisterNodeTypes(Collection ntNames)
+    public void unregisterNodeTypes(Collection ntNames)
             throws NoSuchNodeTypeException, RepositoryException {
+
+        unregisterNodeTypes(ntNames, false);
+    }
+
+    /**
+     * Internal implementation of {@link #unregisterNodeTypes(Collection)}
+     *
+     * @param ntNames a collection of <code>QName</code> objects denoting the
+     *                node types to be unregistered
+     * @param external whether this invocation should be considered external
+     * @throws NoSuchNodeTypeException if any of the specified names does not
+     *                                 denote a registered node type.
+     * @throws RepositoryException if another error occurs
+     */
+    private synchronized void unregisterNodeTypes(Collection ntNames, boolean external)
+            throws NoSuchNodeTypeException, RepositoryException {
+
         // do some preliminary checks
         for (Iterator iter = ntNames.iterator(); iter.hasNext();) {
             QName ntName = (QName) iter.next();
@@ -273,6 +305,11 @@
         // all preconditions are met, node types can now safely be unregistered
         internalUnregister(ntNames);
 
+        // inform cluster if this is not an external invocation
+        if (!external && eventChannel != null) {
+            eventChannel.unregistered(ntNames);
+        }
+
         // persist removal of node type definitions & notify listeners
         for (Iterator iter = ntNames.iterator(); iter.hasNext();) {
             QName ntName = (QName) iter.next();
@@ -307,15 +344,39 @@
     }
 
     /**
-     * @param ntd
-     * @return
-     * @throws NoSuchNodeTypeException
-     * @throws InvalidNodeTypeDefException
-     * @throws RepositoryException
+     * Reregister a node type.
+     * @param ntd node type definition
+     * @return the new effective node type
+     * @throws NoSuchNodeTypeException if <code>ntd</code> refers to an
+     *                                 unknown node type
+     * @throws InvalidNodeTypeDefException if the node type definition
+     *                                     is invalid
+     * @throws RepositoryException if another error occurs
      */
-    public synchronized EffectiveNodeType reregisterNodeType(NodeTypeDef ntd)
+    public EffectiveNodeType reregisterNodeType(NodeTypeDef ntd)
             throws NoSuchNodeTypeException, InvalidNodeTypeDefException,
             RepositoryException {
+
+        return reregisterNodeType(ntd, false);
+    }
+
+    /**
+     * Internal implementation of {@link #reregisterNodeType(NodeTypeDef)}.
+     *
+     * @param ntd node type definition
+     * @param external whether this invocation should be considered external
+     * @return the new effective node type
+     * @throws NoSuchNodeTypeException if <code>ntd</code> refers to an
+     *                                 unknown node type
+     * @throws InvalidNodeTypeDefException if the node type definition
+     *                                     is invalid
+     * @throws RepositoryException if another error occurs
+     */
+    private synchronized EffectiveNodeType reregisterNodeType(NodeTypeDef ntd,
+                                                              boolean external)
+            throws NoSuchNodeTypeException, InvalidNodeTypeDefException,
+            RepositoryException {
+
         QName name = ntd.getName();
         if (!registeredNTDefs.containsKey(name)) {
             throw new NoSuchNodeTypeException(name.toString());
@@ -358,6 +419,11 @@
             // persist node type definitions
             persistCustomNodeTypeDefs(customNTDefs);
 
+            // inform cluster if this is not an external invocation
+            if (!external && eventChannel != null) {
+                eventChannel.reregistered(ntd);
+            }
+
             // notify listeners
             notifyReRegistered(name);
             return entNew;
@@ -608,19 +674,26 @@
     public void externalRegistered(Collection ntDefs)
             throws RepositoryException, InvalidNodeTypeDefException {
 
-        // validate and register new node type definitions
-        internalRegister(ntDefs);
-        // persist new node type definitions
-        for (Iterator iter = ntDefs.iterator(); iter.hasNext();) {
-            NodeTypeDef ntDef = (NodeTypeDef) iter.next();
-            customNTDefs.add(ntDef);
-        }
-        persistCustomNodeTypeDefs(customNTDefs);
-        // notify listeners
-        for (Iterator iter = ntDefs.iterator(); iter.hasNext();) {
-            NodeTypeDef ntDef = (NodeTypeDef) iter.next();
-            notifyRegistered(ntDef.getName());
-        }
+        registerNodeTypes(ntDefs, true);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void externalReregistered(NodeTypeDef ntDef)
+            throws NoSuchNodeTypeException, InvalidNodeTypeDefException,
+            RepositoryException {
+
+        reregisterNodeType(ntDef, true);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void externalUnregistered(Collection ntNames)
+            throws RepositoryException, NoSuchNodeTypeException {
+
+        unregisterNodeTypes(ntNames, true);
     }
 
     //---------------------------------------------------------< overridables >