mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-24 17:32:48 +00:00
Fixed AR-35, AR-213: ContentStore replication driven by quartz
Fixed up sample and WIKI git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@3093 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -11,29 +11,44 @@
|
|||||||
<bean id="backupContentStore"
|
<bean id="backupContentStore"
|
||||||
class="org.alfresco.repo.content.filestore.FileContentStore">
|
class="org.alfresco.repo.content.filestore.FileContentStore">
|
||||||
<constructor-arg>
|
<constructor-arg>
|
||||||
<value>s:/backups/alfresco</value>
|
<value>${dir.contentstore}/../backups/alfresco</value>
|
||||||
</constructor-arg>
|
</constructor-arg>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
<bean id="primaryContentStoreBackupComponent"
|
<bean id="contentStoreReplicator"
|
||||||
class="org.alfresco.repo.content.replication.ContentStoreReplicator"
|
class="org.alfresco.repo.content.replication.ContentStoreReplicator"
|
||||||
depends-on="fileContentStore, backupContentStore"
|
depends-on="fileContentStore, backupContentStore" >
|
||||||
init-method="start">
|
|
||||||
<!-- content source -->
|
<!-- content source -->
|
||||||
<property name="sourceStore">
|
<property name="sourceStore">
|
||||||
<value>fileContentStore</value>
|
<ref bean="fileContentStore" />
|
||||||
</property>
|
</property>
|
||||||
<!-- content target -->
|
<!-- content target -->
|
||||||
<property name="targetStore">
|
<property name="targetStore">
|
||||||
<value>backupContentStore</value>
|
<ref bean="backupContentStore" />
|
||||||
</property>
|
</property>
|
||||||
<!-- set to 'false' to perform a single pass before quitting -->
|
</bean>
|
||||||
<property name="runContinuously">
|
|
||||||
<value>true</value>
|
<bean id="contentStoreBackupTrigger" class="org.alfresco.util.CronTriggerBean">
|
||||||
|
<property name="jobDetail">
|
||||||
|
<bean class="org.springframework.scheduling.quartz.JobDetailBean">
|
||||||
|
<property name="jobClass">
|
||||||
|
<value>org.alfresco.repo.content.replication.ContentStoreReplicator$ContentStoreReplicatorJob</value>
|
||||||
|
</property>
|
||||||
|
<property name="jobDataAsMap">
|
||||||
|
<map>
|
||||||
|
<entry key="contentStoreReplicator">
|
||||||
|
<ref bean="contentStoreReplicator" />
|
||||||
|
</entry>
|
||||||
|
</map>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
</property>
|
</property>
|
||||||
<!-- time between passes -->
|
<property name="scheduler">
|
||||||
<property name="waitTime">
|
<ref bean="schedulerFactory" />
|
||||||
<value>60</value>
|
</property>
|
||||||
|
<!-- trigger at 3am each day -->
|
||||||
|
<property name="cronExpression">
|
||||||
|
<value>0 0 03 * * ?</value>
|
||||||
</property>
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
@@ -18,7 +18,6 @@ package org.alfresco.repo.content.replication;
|
|||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.alfresco.error.AlfrescoRuntimeException;
|
|
||||||
import org.alfresco.repo.content.ContentStore;
|
import org.alfresco.repo.content.ContentStore;
|
||||||
import org.alfresco.repo.node.index.IndexRecovery;
|
import org.alfresco.repo.node.index.IndexRecovery;
|
||||||
import org.alfresco.service.cmr.repository.ContentReader;
|
import org.alfresco.service.cmr.repository.ContentReader;
|
||||||
@@ -48,18 +47,12 @@ public class ContentStoreReplicator
|
|||||||
private ContentStore sourceStore;
|
private ContentStore sourceStore;
|
||||||
private ContentStore targetStore;
|
private ContentStore targetStore;
|
||||||
|
|
||||||
/** used to ensure that this instance gets started once only */
|
/** used to ensure that the threads don't queue up on this component */
|
||||||
private boolean started;
|
private boolean busy;
|
||||||
/** set this on to keep replicating and never stop. The default is <code>true</code>. */
|
|
||||||
private boolean runContinuously;
|
|
||||||
/** the time to wait between passes */
|
|
||||||
private long waitTime;
|
|
||||||
|
|
||||||
public ContentStoreReplicator()
|
public ContentStoreReplicator()
|
||||||
{
|
{
|
||||||
this.started = false;
|
this.busy = false;
|
||||||
this.runContinuously = true;
|
|
||||||
this.waitTime = 60000L;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -83,43 +76,44 @@ public class ContentStoreReplicator
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set whether the thread should run continuously or terminate after
|
* @deprecated use the {@link ContentStoreReplicatorJob job} to trigger
|
||||||
* a first pass.
|
|
||||||
*
|
|
||||||
* @param runContinuously true to run continously (default)
|
|
||||||
*/
|
*/
|
||||||
public void setRunContinuously(boolean runContinuously)
|
public void setRunContinuously(boolean runContinuously)
|
||||||
{
|
{
|
||||||
this.runContinuously = runContinuously;
|
logger.warn(
|
||||||
|
"Property 'runContinuously' has been deprecated.\n" +
|
||||||
|
" Use the " + ContentStoreReplicatorJob.class.getName() + " to trigger");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the time to wait between replication passes (in seconds)
|
* @deprecated use the {@link ContentStoreReplicatorJob job} to trigger
|
||||||
*
|
|
||||||
* @param waitTime the time between passes (in seconds). Default is 60s.
|
|
||||||
*/
|
*/
|
||||||
public void setWaitTime(long waitTime)
|
public void setWaitTime(long waitTime)
|
||||||
{
|
{
|
||||||
// convert to millis
|
logger.warn(
|
||||||
this.waitTime = waitTime * 1000L;
|
"Property 'runContinuously' has been deprecated.\n" +
|
||||||
|
" Use the " + ContentStoreReplicatorJob.class.getName() + " to trigger");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Kick off the replication thread. This method can be used once.
|
* Kick off the replication thread. If one is already busy, then this method does
|
||||||
|
* nothing.
|
||||||
*/
|
*/
|
||||||
public synchronized void start()
|
public synchronized void start()
|
||||||
{
|
{
|
||||||
if (started)
|
if (busy)
|
||||||
{
|
{
|
||||||
throw new AlfrescoRuntimeException("This ContentStoreReplicator has already been started");
|
return;
|
||||||
}
|
}
|
||||||
// create a low-priority, daemon thread to do the work
|
// create a low-priority, daemon thread to do the work
|
||||||
Runnable runnable = new ReplicationRunner();
|
Runnable runnable = new ReplicationRunner();
|
||||||
Thread thread = new Thread(runnable);
|
Thread thread = new Thread(runnable);
|
||||||
|
thread.setName("ContentStoreReplicator");
|
||||||
thread.setPriority(Thread.MIN_PRIORITY);
|
thread.setPriority(Thread.MIN_PRIORITY);
|
||||||
thread.setDaemon(true);
|
thread.setDaemon(true);
|
||||||
// start it
|
// start it
|
||||||
thread.start();
|
thread.start();
|
||||||
|
busy = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -131,38 +125,18 @@ public class ContentStoreReplicator
|
|||||||
{
|
{
|
||||||
public void run()
|
public void run()
|
||||||
{
|
{
|
||||||
// keep this thread going permanently
|
try
|
||||||
while (true)
|
|
||||||
{
|
{
|
||||||
try
|
ContentStoreReplicator.this.replicate();
|
||||||
{
|
}
|
||||||
ContentStoreReplicator.this.replicate();
|
catch (Throwable e)
|
||||||
// check if the process should terminate
|
{
|
||||||
if (!runContinuously)
|
// report
|
||||||
{
|
logger.error("Replication failure", e);
|
||||||
// the thread has caught up with all the available work and should not
|
}
|
||||||
// run continuously
|
finally
|
||||||
if (logger.isDebugEnabled())
|
{
|
||||||
{
|
busy = false;
|
||||||
logger.debug("Thread quitting - first pass of replication complete:");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// pause the the required wait time
|
|
||||||
synchronized(ContentStoreReplicator.this)
|
|
||||||
{
|
|
||||||
ContentStoreReplicator.this.wait(waitTime);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (InterruptedException e)
|
|
||||||
{
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
catch (Throwable e)
|
|
||||||
{
|
|
||||||
// report
|
|
||||||
logger.error("Replication failure", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -246,7 +220,7 @@ public class ContentStoreReplicator
|
|||||||
*
|
*
|
||||||
* @author Derek Hulley
|
* @author Derek Hulley
|
||||||
*/
|
*/
|
||||||
public class ContentStoreReplicatorJob implements Job
|
public static class ContentStoreReplicatorJob implements Job
|
||||||
{
|
{
|
||||||
/** KEY_CONTENT_STORE_REPLICATOR = 'contentStoreReplicator' */
|
/** KEY_CONTENT_STORE_REPLICATOR = 'contentStoreReplicator' */
|
||||||
public static final String KEY_CONTENT_STORE_REPLICATOR = "contentStoreReplicator";
|
public static final String KEY_CONTENT_STORE_REPLICATOR = "contentStoreReplicator";
|
||||||
|
@@ -61,8 +61,6 @@ public class ContentStoreReplicatorTest extends TestCase
|
|||||||
replicator = new ContentStoreReplicator();
|
replicator = new ContentStoreReplicator();
|
||||||
replicator.setSourceStore(sourceStore);
|
replicator.setSourceStore(sourceStore);
|
||||||
replicator.setTargetStore(targetStore);
|
replicator.setTargetStore(targetStore);
|
||||||
replicator.setRunContinuously(false); // replicate once
|
|
||||||
replicator.setWaitTime(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -111,8 +109,6 @@ public class ContentStoreReplicatorTest extends TestCase
|
|||||||
*/
|
*/
|
||||||
public void testContinuousReplication() throws Exception
|
public void testContinuousReplication() throws Exception
|
||||||
{
|
{
|
||||||
replicator.setRunContinuously(true);
|
|
||||||
replicator.setWaitTime(0L);
|
|
||||||
replicator.start();
|
replicator.start();
|
||||||
|
|
||||||
String duplicateUrl = AbstractContentStore.createNewUrl();
|
String duplicateUrl = AbstractContentStore.createNewUrl();
|
||||||
@@ -150,4 +146,15 @@ public class ContentStoreReplicatorTest extends TestCase
|
|||||||
sourceUrls.containsAll(targetUrls);
|
sourceUrls.containsAll(targetUrls);
|
||||||
targetUrls.contains(sourceUrls);
|
targetUrls.contains(sourceUrls);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call the replicator repeatedly to check that it prevents concurrent use
|
||||||
|
*/
|
||||||
|
public void testRepeatedReplication() throws Exception
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
replicator.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user