Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/GarbageCollector.java =================================================================== --- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/GarbageCollector.java (revision 1461410) +++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/GarbageCollector.java (working copy) @@ -18,6 +18,7 @@ import org.apache.jackrabbit.api.management.DataStoreGarbageCollector; import org.apache.jackrabbit.api.management.MarkEventListener; +import org.apache.jackrabbit.core.RepositoryContext; import org.apache.jackrabbit.core.SessionImpl; import org.apache.jackrabbit.core.id.NodeId; import org.apache.jackrabbit.core.id.PropertyId; @@ -96,6 +97,8 @@ private final SessionImpl[] sessionList; private final AtomicBoolean closed = new AtomicBoolean(); + + private final RepositoryContext context; private boolean persistenceManagerScan; @@ -105,14 +108,17 @@ * Create a new garbage collector. * This method is usually not called by the application, it is called * by SessionImpl.createDataStoreGarbageCollector(). - * + * + * @param context repository context * @param dataStore the data store to be garbage-collected * @param list the persistence managers * @param sessionList the sessions to access the workspaces */ - public GarbageCollector( + + public GarbageCollector( RepositoryContext context, DataStore dataStore, IterablePersistenceManager[] list, SessionImpl[] sessionList) { + this.context = context; this.store = dataStore; this.pmList = list; this.persistenceManagerScan = list != null; @@ -232,9 +238,13 @@ } /** - * Stop the observation listener if any are installed. + * Reset modifiedDateOnAccess to 0 and stop the observation + * listener if any are installed. */ public void stopScan() throws RepositoryException { + // reset updateModifiedDateOnAccess to OL + store.updateModifiedDateOnAccess(0L); + if (listeners.size() > 0) { for (Listener listener : listeners) { listener.stop(); @@ -242,6 +252,7 @@ listeners.clear(); } checkObservationException(); + context.setGcRunning(false); } /** Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryContext.java =================================================================== --- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryContext.java (revision 1461410) +++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryContext.java (working copy) @@ -122,6 +122,12 @@ * The Statistics manager, handles statistics */ private StatManager statManager; + + /** + * flag to indicate if GC is running + */ + + private boolean gcRunning; /** * Creates a component context for the given repository. @@ -429,4 +435,22 @@ return statManager; } + /** + * + * @return gcRunning status + */ + public boolean isGcRunning() { + return gcRunning; + } + + /** + * set gcRunnign status + * @param gcRunning + */ + public synchronized void setGcRunning(boolean gcRunning) { + this.gcRunning = gcRunning; + } + + + } Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java =================================================================== --- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java (revision 1461410) +++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java (working copy) @@ -1422,7 +1422,14 @@ } ipmList[i] = (IterablePersistenceManager) pm; } - return new GarbageCollector(context.getDataStore(), ipmList, sessions); + GarbageCollector gc = new GarbageCollector(context, context.getDataStore(), ipmList, sessions); + synchronized (this) { + if (context.isGcRunning()) { + throw new RepositoryException("Cannot create GC. GC already running"); + } + context.setGcRunning(true); + } + return gc; } //-----------------------------------------------------------< Repository > Index: jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/GarbageCollectorTest.java =================================================================== --- jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/GarbageCollectorTest.java (revision 1461410) +++ jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/GarbageCollectorTest.java (working copy) @@ -169,7 +169,36 @@ gc.close(); } + + /** + * Test to validate that two GC cannot run simulatenously. one + * exits throwing exception + */ + public void testSimulatenousRunGC() throws Exception { + Node root = testRootNode; + Session session = root.getSession(); + GCThread gct1 = new GCThread(session); + GCThread gct2 = new GCThread(session); + Thread gcThread1 = new Thread(gct1, "Datastore Garbage Collector 1"); + Thread gcThread2 = new Thread(gct2, "Datastore Garbage Collector 2"); + // run simulatensou gc + gcThread1.start(); + gcThread2.start(); + Thread.sleep(100); + + gct1.setStop(true); + gct2.setStop(true); + + // allow them to complete + gcThread1.join(); + gcThread2.join(); + + // only one should throw error + int count = (gct1.getException() == null ? 0 : 1) + (gct2.getException() == null ? 0 : 1); + assertEquals("only one gc should throw exception ", 1, count); + } + private void runGC(Session session, boolean all) throws Exception { GarbageCollector gc = ((SessionImpl)session).createDataStoreGarbageCollector(); gc.setMarkEventListener(this);