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:
Derek Hulley
2006-06-14 08:49:01 +00:00
parent dd527a2dcf
commit 40c225d3c7
3 changed files with 67 additions and 71 deletions

View File

@@ -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>
<!-- time between passes --> <property name="jobDataAsMap">
<property name="waitTime"> <map>
<value>60</value> <entry key="contentStoreReplicator">
<ref bean="contentStoreReplicator" />
</entry>
</map>
</property>
</bean>
</property>
<property name="scheduler">
<ref bean="schedulerFactory" />
</property>
<!-- trigger at 3am each day -->
<property name="cronExpression">
<value>0 0 03 * * ?</value>
</property> </property>
</bean> </bean>

View File

@@ -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;
} }
/** /**
@@ -130,39 +124,19 @@ public class ContentStoreReplicator
private class ReplicationRunner implements Runnable private class ReplicationRunner implements Runnable
{ {
public void run() public void run()
{
// keep this thread going permanently
while (true)
{ {
try try
{ {
ContentStoreReplicator.this.replicate(); ContentStoreReplicator.this.replicate();
// check if the process should terminate
if (!runContinuously)
{
// the thread has caught up with all the available work and should not
// run continuously
if (logger.isDebugEnabled())
{
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) catch (Throwable e)
{ {
// report // report
logger.error("Replication failure", e); logger.error("Replication failure", e);
} }
finally
{
busy = false;
} }
} }
} }
@@ -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";

View File

@@ -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();
}
}
} }