jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ju...@apache.org
Subject svn commit: r801968 - in /jackrabbit/trunk/jackrabbit-core/src: main/java/org/apache/jackrabbit/core/ main/java/org/apache/jackrabbit/core/persistence/ test/java/org/apache/jackrabbit/core/
Date Fri, 07 Aug 2009 12:27:40 GMT
Author: jukka
Date: Fri Aug  7 12:27:39 2009
New Revision: 801968

URL: http://svn.apache.org/viewvc?rev=801968&view=rev
Log:
JCR-442: Implement a backup tool

Add online backup functionality to RepositoryCopier. It's now possible to copy a (read-only)
repository while it's still running.

Modified:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryCopier.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/PersistenceCopier.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/RepositoryCopierTest.java

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryCopier.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryCopier.java?rev=801968&r1=801967&r2=801968&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryCopier.java
(original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryCopier.java
Fri Aug  7 12:27:39 2009
@@ -27,12 +27,10 @@
 
 import org.apache.commons.io.FileUtils;
 import org.apache.jackrabbit.core.config.RepositoryConfig;
-import org.apache.jackrabbit.core.data.DataStore;
 import org.apache.jackrabbit.core.nodetype.InvalidNodeTypeDefException;
 import org.apache.jackrabbit.core.nodetype.NodeTypeDef;
 import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
 import org.apache.jackrabbit.core.persistence.PersistenceCopier;
-import org.apache.jackrabbit.core.version.InternalVersionManagerImpl;
 import org.apache.jackrabbit.spi.Name;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -41,6 +39,14 @@
  * Tool for backing up or migrating the entire contents (workspaces,
  * version histories, namespaces, node types, etc.) of a repository to
  * a new repository. The target repository (if it exists) is overwritten.
+ * <p>
+ * No cluster journal records are written in the target repository. If the
+ * target repository is clustered, it should be the only node in the cluster.
+ * <p>
+ * The target repository needs to be fully reindexed after the copy operation.
+ * The static copy() methods will remove the target search index folders from
+ * their default locations to trigger automatic reindexing when the repository
+ * is next started.
  *
  * @since Apache Jackrabbit 1.6
  */
@@ -53,30 +59,110 @@
         LoggerFactory.getLogger(RepositoryCopier.class);
 
     /**
-     * Source repository configuration
+     * Source repository.
      */
-    private final RepositoryConfig sourceConfig;
+    private final RepositoryImpl source;
 
     /**
-     * Target repository configuration
+     * Target repository.
      */
-    private final RepositoryConfig targetConfig;
+    private final RepositoryImpl target;
 
     /**
-     * Creates a tool for copying the full contents of the source repository.
-     * The given source repository directory is expected to contain the
-     * repository configuration as a <code>repository.xml</code> file.
-     * The target repository directory should not already exist. It will be
-     * automatically created with default repository configuration.
+     * Copies the contents of the repository in the given source directory
+     * to a repository in the given target directory.
      *
      * @param source source repository directory
      * @param target target repository directory
-     * @throws RepositoryException if the repositories can not be accessed
+     * @throws RepositoryException if the copy operation fails
+     * @throws IOException if the target repository can not be initialized
+     */
+    public static void copy(File source, File target)
+            throws RepositoryException, IOException {
+        copy(RepositoryConfig.create(source), RepositoryConfig.install(target));
+    }
+
+    /**
+     * Copies the contents of the repository with the given configuration
+     * to a repository in the given target directory.
+     *
+     * @param source source repository configuration
+     * @param target target repository directory
+     * @throws RepositoryException if the copy operation fails
+     * @throws IOException if the target repository can not be initialized
+     */
+    public static void copy(RepositoryConfig source, File target)
+            throws RepositoryException, IOException {
+        copy(source, RepositoryConfig.install(target));
+    }
+
+    /**
+     * Copies the contents of the source repository with the given
+     * configuration to a target repository with the given configuration.
+     *
+     * @param source source repository configuration
+     * @param target target repository directory
+     * @throws RepositoryException if the copy operation fails
+     */
+    public static void copy(RepositoryConfig source, RepositoryConfig target)
+            throws RepositoryException {
+        RepositoryImpl repository = RepositoryImpl.create(source);
+        try {
+            copy(repository, target);
+        } finally {
+            repository.shutdown();
+        }
+    }
+
+    /**
+     * Copies the contents of the given source repository to a repository in
+     * the given target directory.
+     * <p>
+     * The source repository <strong>must not be modified</strong> while
+     * the copy operation is running to avoid an inconsistent copy.
+     *
+     * @param source source repository directory
+     * @param target target repository directory
+     * @throws RepositoryException if the copy operation fails
      * @throws IOException if the target repository can not be initialized
      */
-    public RepositoryCopier(File source, File target)
+    public static void copy(RepositoryImpl source, File target)
             throws RepositoryException, IOException {
-        this(RepositoryConfig.create(source), RepositoryConfig.install(target));
+        copy(source, RepositoryConfig.install(target));
+    }
+
+    /**
+     * Copies the contents of the given source repository to a target
+     * repository with the given configuration.
+     * <p>
+     * The source repository <strong>must not be modified</strong> while
+     * the copy operation is running to avoid an inconsistent copy.
+     *
+     * @param source source repository directory
+     * @param target target repository directory
+     * @throws RepositoryException if the copy operation fails
+     * @throws IOException if the target repository can not be initialized
+     */
+    public static void copy(RepositoryImpl source, RepositoryConfig target)
+            throws RepositoryException {
+        RepositoryImpl repository = RepositoryImpl.create(target);
+        try {
+            new RepositoryCopier(source, repository).copy();
+        } finally {
+            repository.shutdown();
+        }
+
+        // Remove index directories to force re-indexing on next startup
+        // TODO: There should be a cleaner way to do this
+        File targetDir = new File(target.getHomeDir());
+        File repoDir = new File(targetDir, "repository");
+        FileUtils.deleteQuietly(new File(repoDir, "index"));
+        File[] workspaces = new File(targetDir, "workspaces").listFiles();
+        if (workspaces != null) {
+            for (File workspace : workspaces) {
+                FileUtils.deleteQuietly(new File(workspace, "index"));
+            }
+        }
     }
 
     /**
@@ -84,18 +170,22 @@
      * to the given target repository. Any existing content in the target
      * repository will be overwritten.
      *
-     * @param source source repository configuration
-     * @param target target repository configuration
-     * @throws RepositoryException if the repositories can not be accessed
+     * @param source source repository
+     * @param target target repository
      */
-    public RepositoryCopier(RepositoryConfig source, RepositoryConfig target)
-            throws RepositoryException {
-        sourceConfig = source;
-        targetConfig = target;
+    public RepositoryCopier(RepositoryImpl source, RepositoryImpl target) {
+        this.source = source;
+        this.target = target;
     }
 
     /**
      * Copies the full content from the source to the target repository.
+     * <p>
+     * The source repository <strong>must not be modified</strong> while
+     * the copy operation is running to avoid an inconsistent copy.
+     * <p>
+     * This method leaves the search indexes of the target repository in
+     * an 
      * Note that both the source and the target repository must be closed
      * during the copy operation as this method requires exclusive access
      * to the repositories.
@@ -105,89 +195,64 @@
     public void copy() throws RepositoryException {
         logger.info(
                 "Copying repository content from {} to {}",
-                sourceConfig.getHomeDir(), targetConfig.getHomeDir());
-
-        RepositoryImpl source = RepositoryImpl.create(sourceConfig);
+                source.repConfig.getHomeDir(),
+                target.repConfig.getHomeDir());
         try {
-            RepositoryImpl target = RepositoryImpl.create(targetConfig);
-            try {
-                copyNamespaces(
-                        source.getNamespaceRegistry(),
-                        target.getNamespaceRegistry());
-                copyNodeTypes(
-                        source.getNodeTypeRegistry(),
-                        target.getNodeTypeRegistry());
-                copyVersionStore(
-                        source.getVersionManagerImpl(),
-                        target.getVersionManagerImpl(),
-                        target.getDataStore());
-                copyWorkspaces(source, target);
-            } catch (Exception e) {
-                throw new RepositoryException("Failed to copy content", e);
-            } finally {
-                target.shutdown();
-            }
-
-            // Remove index directories to force re-indexing on next startup
-            // TODO: There should be a cleaner way to do this
-            File targetDir = new File(targetConfig.getHomeDir());
-            File repoDir = new File(targetDir, "repository");
-            FileUtils.deleteQuietly(new File(repoDir, "index"));
-            File[] workspaces = new File(targetDir, "workspaces").listFiles();
-            if (workspaces != null) {
-                for (File workspace : workspaces) {
-                    FileUtils.deleteQuietly(new File(workspace, "index"));
-                }
-            }
-        } finally {
-            source.shutdown();
+            copyNamespaces();
+            copyNodeTypes();
+            copyVersionStore();
+            copyWorkspaces();
+        } catch (Exception e) {
+            throw new RepositoryException("Failed to copy content", e);
         }
     }
 
-    private void copyNamespaces(
-            NamespaceRegistry source, NamespaceRegistry target)
-            throws RepositoryException {
-        logger.info("Copying registered namespaces");
+    private void copyNamespaces() throws RepositoryException {
+        NamespaceRegistry sourceRegistry = source.getNamespaceRegistry();
+        NamespaceRegistry targetRegistry = target.getNamespaceRegistry();
 
-        Collection<String> existing = Arrays.asList(target.getURIs());
-        for (String uri : source.getURIs()) {
+        logger.info("Copying registered namespaces");
+        Collection<String> existing = Arrays.asList(targetRegistry.getURIs());
+        for (String uri : sourceRegistry.getURIs()) {
             if (!existing.contains(uri)) {
                 // TODO: what if the prefix is already taken?
-                target.registerNamespace(source.getPrefix(uri), uri);
+                targetRegistry.registerNamespace(
+                        sourceRegistry.getPrefix(uri), uri);
             }
         }
     }
 
-    private void copyNodeTypes(NodeTypeRegistry source, NodeTypeRegistry target)
-            throws RepositoryException, InvalidNodeTypeDefException {
-        logger.info("Copying registered node types");
+    private void copyNodeTypes() throws RepositoryException {
+        NodeTypeRegistry sourceRegistry = source.getNodeTypeRegistry();
+        NodeTypeRegistry targetRegistry = target.getNodeTypeRegistry();
 
+        logger.info("Copying registered node types");
         Collection<Name> existing =
-            Arrays.asList(target.getRegisteredNodeTypes());
+            Arrays.asList(targetRegistry.getRegisteredNodeTypes());
         Collection<NodeTypeDef> register = new ArrayList<NodeTypeDef>();
-        for (Name name : source.getRegisteredNodeTypes()) {
+        for (Name name : sourceRegistry.getRegisteredNodeTypes()) {
             // TODO: what about modified node types?
             if (!existing.contains(name)) {
-                register.add(source.getNodeTypeDef(name));
+                register.add(sourceRegistry.getNodeTypeDef(name));
             }
         }
-        target.registerNodeTypes(register);
+        try {
+            targetRegistry.registerNodeTypes(register);
+        } catch (InvalidNodeTypeDefException e) {
+            throw new RepositoryException("Unable to copy node types", e);
+        }
     }
 
-    private void copyVersionStore(
-            InternalVersionManagerImpl source,
-            InternalVersionManagerImpl target, DataStore store)
-            throws Exception {
+    private void copyVersionStore() throws RepositoryException {
         logger.info("Copying version histories");
-
         PersistenceCopier copier = new PersistenceCopier(
-                source.getPersistenceManager(),
-                target.getPersistenceManager(), store);
+                source.getVersionManagerImpl().getPersistenceManager(),
+                target.getVersionManagerImpl().getPersistenceManager(),
+                target.getDataStore());
         copier.copy(RepositoryImpl.VERSION_STORAGE_NODE_ID);
     }
 
-    private void copyWorkspaces(RepositoryImpl source, RepositoryImpl target)
-            throws Exception {
+    private void copyWorkspaces() throws RepositoryException {
         Collection<String> existing = Arrays.asList(target.getWorkspaceNames());
         for (String name : source.getWorkspaceNames()) {
             logger.info("Copying workspace {}" , name);

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/PersistenceCopier.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/PersistenceCopier.java?rev=801968&r1=801967&r2=801968&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/PersistenceCopier.java
(original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/PersistenceCopier.java
Fri Aug  7 12:27:39 2009
@@ -16,17 +16,20 @@
  */
 package org.apache.jackrabbit.core.persistence;
 
+import java.io.IOException;
 import java.io.InputStream;
 import java.util.HashSet;
 import java.util.Set;
 
 import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
 
 import org.apache.jackrabbit.core.data.DataStore;
 import org.apache.jackrabbit.core.id.NodeId;
 import org.apache.jackrabbit.core.id.PropertyId;
 import org.apache.jackrabbit.core.state.ChangeLog;
 import org.apache.jackrabbit.core.state.ChildNodeEntry;
+import org.apache.jackrabbit.core.state.ItemStateException;
 import org.apache.jackrabbit.core.state.NodeReferences;
 import org.apache.jackrabbit.core.state.NodeState;
 import org.apache.jackrabbit.core.state.PropertyState;
@@ -96,18 +99,22 @@
      * are automatically skipped.
      *
      * @param id identifier of the node to be copied
-     * @throws Exception if the copy operation fails
+     * @throws RepositoryException if the copy operation fails
      */
-    public void copy(NodeId id) throws Exception {
+    public void copy(NodeId id) throws RepositoryException {
         if (!exclude.contains(id)) {
-            NodeState node = source.load(id);
+            try {
+                NodeState node = source.load(id);
 
-            for (ChildNodeEntry entry : node.getChildNodeEntries()) {
-                copy(entry.getId());
-            }
+                for (ChildNodeEntry entry : node.getChildNodeEntries()) {
+                    copy(entry.getId());
+                }
 
-            copy(node);
-            exclude.add(id);
+                copy(node);
+                exclude.add(id);
+            } catch (ItemStateException e) {
+                throw new RepositoryException("Unable to copy " + id, e);
+            }
         }
     }
 
@@ -116,64 +123,71 @@
      * to the target persistence manager.
      *
      * @param sourceNode source node state
-     * @throws Exception if the copy operation fails
+     * @throws RepositoryException if the copy operation fails
      */
-    private void copy(NodeState sourceNode) throws Exception {
-        ChangeLog changes = new ChangeLog();
-
-        // Copy the node state
-        NodeState targetNode = target.createNew(sourceNode.getNodeId());
-        targetNode.setParentId(sourceNode.getParentId());
-        targetNode.setDefinitionId(sourceNode.getDefinitionId());
-        targetNode.setNodeTypeName(sourceNode.getNodeTypeName());
-        targetNode.setMixinTypeNames(sourceNode.getMixinTypeNames());
-        targetNode.setPropertyNames(sourceNode.getPropertyNames());
-        targetNode.setChildNodeEntries(sourceNode.getChildNodeEntries());
-        if (target.exists(targetNode.getNodeId())) {
-            changes.modified(targetNode);
-        } else {
-            changes.added(targetNode);
-        }
+    private void copy(NodeState sourceNode) throws RepositoryException {
+        try {
+            ChangeLog changes = new ChangeLog();
+
+            // Copy the node state
+            NodeState targetNode = target.createNew(sourceNode.getNodeId());
+            targetNode.setParentId(sourceNode.getParentId());
+            targetNode.setDefinitionId(sourceNode.getDefinitionId());
+            targetNode.setNodeTypeName(sourceNode.getNodeTypeName());
+            targetNode.setMixinTypeNames(sourceNode.getMixinTypeNames());
+            targetNode.setPropertyNames(sourceNode.getPropertyNames());
+            targetNode.setChildNodeEntries(sourceNode.getChildNodeEntries());
+            if (target.exists(targetNode.getNodeId())) {
+                changes.modified(targetNode);
+            } else {
+                changes.added(targetNode);
+            }
 
-        // Copy all associated property states
-        for (Name name : sourceNode.getPropertyNames()) {
-            PropertyId id = new PropertyId(sourceNode.getNodeId(), name);
-            PropertyState sourceState = source.load(id);
-            PropertyState targetState = target.createNew(id);
-            targetState.setDefinitionId(sourceState.getDefinitionId());
-            targetState.setType(sourceState.getType());
-            targetState.setMultiValued(sourceState.isMultiValued());
-            InternalValue[] values = sourceState.getValues();
-            if (sourceState.getType() == PropertyType.BINARY) {
-                for (int i = 0; i < values.length; i++) {
-                    InputStream stream = values[i].getStream();
-                    try {
-                        values[i] = InternalValue.create(stream, store);
-                    } finally {
-                        stream.close();
+            // Copy all associated property states
+            for (Name name : sourceNode.getPropertyNames()) {
+                PropertyId id = new PropertyId(sourceNode.getNodeId(), name);
+                PropertyState sourceState = source.load(id);
+                PropertyState targetState = target.createNew(id);
+                targetState.setDefinitionId(sourceState.getDefinitionId());
+                targetState.setType(sourceState.getType());
+                targetState.setMultiValued(sourceState.isMultiValued());
+                InternalValue[] values = sourceState.getValues();
+                if (sourceState.getType() == PropertyType.BINARY) {
+                    for (int i = 0; i < values.length; i++) {
+                        InputStream stream = values[i].getStream();
+                        try {
+                            values[i] = InternalValue.create(stream, store);
+                        } finally {
+                            stream.close();
+                        }
                     }
                 }
+                targetState.setValues(values);
+                if (target.exists(targetState.getPropertyId())) {
+                    changes.modified(targetState);
+                } else {
+                    changes.added(targetState);
+                }
             }
-            targetState.setValues(values);
-            if (target.exists(targetState.getPropertyId())) {
-                changes.modified(targetState);
-            } else {
-                changes.added(targetState);
+
+            // Copy all node references
+            if (source.existsReferencesTo(sourceNode.getNodeId())) {
+                changes.modified(source.loadReferencesTo(sourceNode.getNodeId()));
+            } else if (target.existsReferencesTo(sourceNode.getNodeId())) {
+                NodeReferences references =
+                    target.loadReferencesTo(sourceNode.getNodeId());
+                references.clearAllReferences();
+                changes.modified(references);
             }
-        }
 
-        // Copy all node references
-        if (source.existsReferencesTo(sourceNode.getNodeId())) {
-            changes.modified(source.loadReferencesTo(sourceNode.getNodeId()));
-        } else if (target.existsReferencesTo(sourceNode.getNodeId())) {
-            NodeReferences references =
-                target.loadReferencesTo(sourceNode.getNodeId());
-            references.clearAllReferences();
-            changes.modified(references);
+            // Persist the copied states
+            target.store(changes);
+        } catch (IOException e) {
+            throw new RepositoryException(
+                    "Unable to copy binary values of " + sourceNode, e);
+        } catch (ItemStateException e) {
+            throw new RepositoryException("Unable to copy " + sourceNode, e);
         }
-
-        // Persist the copied states
-        target.store(changes);
     }
 
 }

Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/RepositoryCopierTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/RepositoryCopierTest.java?rev=801968&r1=801967&r2=801968&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/RepositoryCopierTest.java
(original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/RepositoryCopierTest.java
Fri Aug  7 12:27:39 2009
@@ -71,7 +71,7 @@
 
     public void testRepositoryCopy() throws Exception {
         createSourceRepository();
-        new RepositoryCopier(SOURCE, TARGET).copy();
+        RepositoryCopier.copy(SOURCE, TARGET);
         verifyTargetRepository();
     }
 



Mime
View raw message