### Eclipse Workspace Patch 1.0 #P jackrabbit-core-2.2 Index: src/main/java/org/apache/jackrabbit/core/data/GarbageCollector.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/data/GarbageCollector.java (revision 1350183) +++ src/main/java/org/apache/jackrabbit/core/data/GarbageCollector.java (working copy) @@ -76,7 +76,7 @@ public class GarbageCollector implements DataStoreGarbageCollector { /** logger instance */ - private static final Logger LOG = LoggerFactory.getLogger(GarbageCollector.class); + static final Logger LOG = LoggerFactory.getLogger(GarbageCollector.class); private MarkEventListener callback; @@ -98,6 +98,9 @@ private boolean persistenceManagerScan; + private volatile RepositoryException observationException; + + /** * Create a new garbage collector. * This method is usually not called by the application, it is called @@ -178,7 +181,7 @@ // add a listener to get 'new' nodes // actually, new nodes are not the problem, but moved nodes - listeners.add(new Listener(session)); + listeners.add(new Listener(this, session)); // adding a link to a BLOB updates the modified date // reading usually doesn't, but when scanning, it does @@ -234,14 +237,11 @@ public void stopScan() throws RepositoryException { if (listeners.size() > 0) { for (Listener listener : listeners) { - try { - listener.stop(); - } catch (Exception e) { - throw new RepositoryException(e); - } + listener.stop(); } listeners.clear(); } + checkObservationException(); } /** @@ -309,6 +309,7 @@ } catch (InvalidItemStateException e) { LOG.debug("Node removed concurrently - ignoring", e); } + checkObservationException(); } private void rememberNode(String path) { @@ -368,6 +369,24 @@ } } + private void checkObservationException() throws RepositoryException { + RepositoryException e = observationException; + if (e != null) { + observationException = null; + String message = "Exception while processing concurrent events"; + LOG.warn(message, e); + e = new RepositoryException(message, e); + } + } + + void onObservationException(Exception e) { + if (e instanceof RepositoryException) { + observationException = (RepositoryException) e; + } else { + observationException = new RepositoryException(e); + } + } + /** * Auto-close in case the application didn't call it explicitly. */ @@ -382,26 +401,23 @@ */ class Listener implements SynchronousEventListener { + private final GarbageCollector gc; private final Session session; - private final ObservationManager manager; - private Exception lastException; - - Listener(Session session) + Listener(GarbageCollector gc, Session session) throws UnsupportedRepositoryOperationException, RepositoryException { + this.gc = gc; this.session = session; Workspace ws = session.getWorkspace(); manager = ws.getObservationManager(); + // Event.NODE_ADDED also includes moved nodes manager.addEventListener(this, Event.NODE_ADDED, "/", true, null, null, false); } - void stop() throws Exception { - if (lastException != null) { - throw lastException; - } + void stop() throws RepositoryException { manager.removeEventListener(this); } @@ -427,7 +443,12 @@ // ignore } } catch (Exception e) { - lastException = e; + gc.onObservationException(e); + try { + stop(); + } catch (RepositoryException e2) { + LOG.warn("Exception removing the observation listener - ignored", e2); + } } } }