You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by bd...@apache.org on 2009/08/27 17:19:13 UTC
svn commit: r808453 - in /sling/trunk/installer/jcr/jcrinstall/src:
main/java/org/apache/sling/jcr/jcrinstall/impl/
test/java/org/apache/sling/jcr/jcrinstall/impl/
Author: bdelacretaz
Date: Thu Aug 27 15:19:08 2009
New Revision: 808453
URL: http://svn.apache.org/viewvc?rev=808453&view=rev
Log:
SLING-1078 - avoid unnecessary scans in JcrInstaller.run() loop
Added:
sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/RescanTimer.java (with props)
sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/RootFolderListener.java
- copied, changed from r808152, sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/WatchedFolderCreationListener.java
sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/ScanningLoopTest.java (with props)
Removed:
sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/WatchedFolderCreationListener.java
Modified:
sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/JcrInstaller.java
sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/WatchedFolder.java
sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/ContentHelper.java
sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/FindPathsToWatchTest.java
sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/MiscUtil.java
sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/ResourceDetectionTest.java
Modified: sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/JcrInstaller.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/JcrInstaller.java?rev=808453&r1=808452&r2=808453&view=diff
==============================================================================
--- sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/JcrInstaller.java (original)
+++ sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/JcrInstaller.java Thu Aug 27 15:19:08 2009
@@ -61,6 +61,13 @@
public static final String URL_SCHEME = "jcrinstall";
private final Logger log = LoggerFactory.getLogger(getClass());
+
+ /** Counters, used for statistics and testing */
+ private final long [] counters = new long[COUNTERS_COUNT];
+ public static final int SCAN_FOLDERS_COUNTER = 0;
+ public static final int UPDATE_FOLDERS_LIST_COUNTER = 1;
+ public static final int RUN_LOOP_COUNTER = 2;
+ public static final int COUNTERS_COUNT = 3;
/** This class watches the repository for installable resources
* @scr.reference
@@ -110,9 +117,6 @@
/** Session shared by all WatchedFolder */
private Session session;
- /** Count cycles of our run() method, used in testing */
- private int cyclesCount;
-
/** Used to stop background thread when deactivated */
private int deactivationCounter = 1;
@@ -125,8 +129,11 @@
private final Collection <NodeConverter> converters = new ArrayList<NodeConverter>();
/** Detect newly created folders that we must watch */
- private final List<WatchedFolderCreationListener> listeners = new LinkedList<WatchedFolderCreationListener>();
+ private final List<RootFolderListener> listeners = new LinkedList<RootFolderListener>();
+ /** Timer used to call updateFoldersList() */
+ private final RescanTimer updateFoldersListTimer = new RescanTimer();
+
protected void activate(ComponentContext context) throws Exception {
log.info("activate()");
@@ -170,7 +177,7 @@
// Setup folder filtering and watching
folderNameFilter = new FolderNameFilter(roots, folderNameRegexp, runMode);
for (String path : roots) {
- listeners.add(new WatchedFolderCreationListener(session, folderNameFilter, path));
+ listeners.add(new RootFolderListener(session, folderNameFilter, path, updateFoldersListTimer));
}
// Find paths to watch and create WatchedFolders to manage them
@@ -204,7 +211,7 @@
watchedFolders = null;
converters.clear();
if(session != null) {
- for(WatchedFolderCreationListener wfc : listeners) {
+ for(RootFolderListener wfc : listeners) {
wfc.cleanup(session);
}
session.logout();
@@ -259,7 +266,7 @@
}
final int depth = path.split("/").length;
if(depth > maxWatchedFolderDepth) {
- log.debug("Not recursing into {} due to maxWatchedFolderDepth={}", path, maxWatchedFolderDepth);
+ log.info("Not recursing into {} due to maxWatchedFolderDepth={}", path, maxWatchedFolderDepth);
return;
} else {
final NodeIterator it = n.getNodes();
@@ -283,15 +290,27 @@
* @return a list of InstallableResource that must be unregistered,
* for folders that have been removed
*/
- private List<InstallableResource> addAndDeleteFolders() throws Exception {
+ private List<InstallableResource> updateFoldersList() throws Exception {
final List<InstallableResource> result = new LinkedList<InstallableResource>();
- for(WatchedFolderCreationListener wfc : listeners) {
- final Set<String> newPaths = wfc.getAndClearPaths();
- if(newPaths != null && newPaths.size() > 0) {
- log.info("Detected {} new folder(s) to watch", newPaths.size());
- for(String path : newPaths) {
- watchedFolders.add(
- new WatchedFolder(session, path, folderNameFilter.getPriority(path), URL_SCHEME, converters));
+ for(RootFolderListener wfc : listeners) {
+ final Set<String> changedPaths = wfc.getAndClearPaths();
+ if(changedPaths != null && changedPaths.size() > 0) {
+ log.debug("Detected {} paths with possible watched folder changes", changedPaths.size());
+ for(String path : changedPaths) {
+ // Deletions are handled below
+ if(folderNameFilter.getPriority(path) > 0 && session.itemExists(path)) {
+ WatchedFolder existing = null;
+ for(WatchedFolder wf : watchedFolders) {
+ if(wf.getPath().equals(path)) {
+ existing = wf;
+ break;
+ }
+ }
+ if(existing == null) {
+ watchedFolders.add(
+ new WatchedFolder(session, path, folderNameFilter.getPriority(path), URL_SCHEME, converters));
+ }
+ }
}
}
}
@@ -299,13 +318,13 @@
final List<WatchedFolder> toRemove = new ArrayList<WatchedFolder>();
for(WatchedFolder wf : watchedFolders) {
if(!session.itemExists(wf.getPath())) {
- log.info("Deleting {}, path does not exist anymore", wf);
result.addAll(wf.scan().toRemove);
wf.cleanup();
toRemove.add(wf);
}
}
for(WatchedFolder wf : toRemove) {
+ log.info("Deleting {}, path does not exist anymore", wf);
watchedFolders.remove(wf);
}
@@ -318,15 +337,15 @@
final int savedCounter = deactivationCounter;
while(savedCounter == deactivationCounter) {
try {
- final List<InstallableResource> toRemove = addAndDeleteFolders();
- for(InstallableResource r : toRemove) {
- log.info("Removing resource from OSGi installer (folder deleted): {}",r);
- installer.removeResource(r);
- }
-
// Rescan WatchedFolders if needed
- if(System.currentTimeMillis() > WatchedFolder.getNextScanTime()) {
+ final boolean scanWf = WatchedFolder.getRescanTimer().expired();
+ if(scanWf) {
for(WatchedFolder wf : watchedFolders) {
+ if(!wf.needsScan()) {
+ continue;
+ }
+ WatchedFolder.getRescanTimer().reset();
+ counters[SCAN_FOLDERS_COUNTER]++;
final WatchedFolder.ScanResult sr = wf.scan();
for(InstallableResource r : sr.toRemove) {
log.info("Removing resource from OSGi installer: {}",r);
@@ -338,9 +357,19 @@
}
}
}
- cyclesCount++;
- // TODO wait for events from our listeners, and/or WatchedFolder scan time
+ // Update list of WatchedFolder if we got any relevant events,
+ // or if there were any WatchedFolder events
+ if(scanWf || updateFoldersListTimer.expired()) {
+ updateFoldersListTimer.reset();
+ counters[UPDATE_FOLDERS_LIST_COUNTER]++;
+ final List<InstallableResource> toRemove = updateFoldersList();
+ for(InstallableResource r : toRemove) {
+ log.info("Removing resource from OSGi installer (folder deleted): {}",r);
+ installer.removeResource(r);
+ }
+ }
+
try {
Thread.sleep(RUN_LOOP_DELAY_MSEC);
} catch(InterruptedException ignore) {
@@ -353,8 +382,13 @@
} catch(InterruptedException ignore) {
}
}
+ counters[RUN_LOOP_COUNTER]++;
}
- log.info("Background thread {} stopping", Thread.currentThread().getName());
+ log.info("Background thread {} done", Thread.currentThread().getName());
+ counters[RUN_LOOP_COUNTER] = -1;
+ }
+
+ long [] getCounters() {
+ return counters;
}
-
}
\ No newline at end of file
Added: sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/RescanTimer.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/RescanTimer.java?rev=808453&view=auto
==============================================================================
--- sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/RescanTimer.java (added)
+++ sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/RescanTimer.java Thu Aug 27 15:19:08 2009
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.jcr.jcrinstall.impl;
+
+/** Used to wait at least SCAN_DELAY_MSEC before rescanning
+ * things after receiving a JCR Event. This avoids useless
+ * scanning, as events usually come in bursts.
+ */
+
+class RescanTimer {
+ public static final long SCAN_DELAY_MSEC = 500L;
+ private long nextScanTime = Long.MAX_VALUE;
+
+ synchronized void scheduleScan() {
+ nextScanTime = System.currentTimeMillis() + SCAN_DELAY_MSEC;
+ }
+
+ synchronized void reset() {
+ nextScanTime = Long.MAX_VALUE;
+ }
+
+ boolean expired() {
+ return System.currentTimeMillis() > nextScanTime;
+ }
+}
Propchange: sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/RescanTimer.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/RescanTimer.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision Rev URL
Copied: sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/RootFolderListener.java (from r808152, sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/WatchedFolderCreationListener.java)
URL: http://svn.apache.org/viewvc/sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/RootFolderListener.java?p2=sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/RootFolderListener.java&p1=sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/WatchedFolderCreationListener.java&r1=808152&r2=808453&rev=808453&view=diff
==============================================================================
--- sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/WatchedFolderCreationListener.java (original)
+++ sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/RootFolderListener.java Thu Aug 27 15:19:08 2009
@@ -30,24 +30,34 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-/** Listen for JCR events to find out when new WatchedFolders
- * must be created.
+/** Listen for JCR events under one of our roots, to find out
+ * when new WatchedFolders must be created, or when some might
+ * have been deleted.
*/
-class WatchedFolderCreationListener implements EventListener {
+class RootFolderListener implements EventListener {
protected final Logger log = LoggerFactory.getLogger(this.getClass());
private Set<String> paths = new HashSet<String>();
private final FolderNameFilter folderNameFilter;
+ private final RescanTimer timer;
+ private final String watchedPath;
- WatchedFolderCreationListener(Session session, FolderNameFilter fnf, String path) throws RepositoryException {
+ RootFolderListener(Session session, FolderNameFilter fnf, String path, RescanTimer timer) throws RepositoryException {
folderNameFilter = fnf;
+ this.timer = timer;
+ this.watchedPath = path;
- int eventTypes = Event.NODE_ADDED;
+ int eventTypes = Event.NODE_ADDED | Event.NODE_REMOVED;
boolean isDeep = true;
boolean noLocal = true;
session.getWorkspace().getObservationManager().addEventListener(this, eventTypes, path,
isDeep, null, null, noLocal);
}
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + " (" + watchedPath + ")";
+ }
+
void cleanup(Session session) throws RepositoryException {
session.getWorkspace().getObservationManager().removeEventListener(this);
}
@@ -72,7 +82,10 @@
try {
while(it.hasNext()) {
final Event e = it.nextEvent();
- if(folderNameFilter.getPriority(e.getPath()) > 0) {
+ // Rescan on all NODE_REMOVED events, to be on the safe side:
+ // an install folder might have been removed, and (I think) this is
+ // the safest way of finding out.
+ if(e.getType() == Event.NODE_REMOVED || folderNameFilter.getPriority(e.getPath()) > 0) {
synchronized(paths) {
paths.add(e.getPath());
}
@@ -81,5 +94,7 @@
} catch(RepositoryException re) {
log.warn("RepositoryException in onEvent", re);
}
+ log.debug("{} got JCR events, scheduling rescan of {}", this, paths);
+ timer.scheduleScan();
}
}
Modified: sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/WatchedFolder.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/WatchedFolder.java?rev=808453&r1=808452&r2=808453&view=diff
==============================================================================
--- sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/WatchedFolder.java (original)
+++ sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/WatchedFolder.java Thu Aug 27 15:19:08 2009
@@ -46,7 +46,7 @@
private final String path;
private final int priority;
private final Session session;
- private static long nextScanTime;
+ private static RescanTimer rescanTimer = new RescanTimer();
private boolean needsScan;
private final String urlScheme;
private final Collection <JcrInstaller.NodeConverter> converters;
@@ -61,12 +61,12 @@
/** Store the digests of the last returned resources, keyed by path, to detect changes */
private final Map<String, String> digests = new HashMap<String, String>();
- // WatchedFolders that need a rescan will be scanned
- // once no JCR events have been received for this amount of time.
- public static final long SCAN_DELAY_MSEC = 500L;
-
WatchedFolder(Session session, String path, int priority,
String urlScheme, Collection<JcrInstaller.NodeConverter> converters) throws RepositoryException {
+ if(priority < 1) {
+ throw new IllegalArgumentException("Cannot watch folder with priority 0:" + path);
+ }
+
this.path = path;
this.converters = converters;
this.priority = priority;
@@ -105,7 +105,7 @@
/** Set a static "timer" whenever an event occurs */
public void onEvent(EventIterator it) {
- nextScanTime = System.currentTimeMillis() + SCAN_DELAY_MSEC;
+ rescanTimer.scheduleScan();
needsScan = true;
log.debug("Event received, scheduling scan of {}", path);
}
@@ -114,13 +114,14 @@
return needsScan;
}
- static long getNextScanTime() {
- return nextScanTime;
+ static RescanTimer getRescanTimer() {
+ return rescanTimer;
}
/** Scan the contents of our folder and return the corresponding InstallableResource */
ScanResult scan() throws Exception {
log.debug("Scanning {}", path);
+ needsScan = false;
Node folder = null;
if(session.itemExists(path)) {
Modified: sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/ContentHelper.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/ContentHelper.java?rev=808453&r1=808452&r2=808453&view=diff
==============================================================================
--- sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/ContentHelper.java (original)
+++ sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/ContentHelper.java Thu Aug 27 15:19:08 2009
@@ -94,12 +94,7 @@
void setupContent() throws Exception {
cleanupContent();
- for(String folder : WATCHED_FOLDERS) {
- createFolder(folder);
- }
- for(String folder : IGNORED_FOLDERS) {
- createFolder(folder);
- }
+ setupFolders();
for(String path : FAKE_RESOURCES) {
createOrUpdateFile(path);
}
@@ -108,6 +103,15 @@
}
}
+ void setupFolders() throws Exception {
+ for(String folder : WATCHED_FOLDERS) {
+ createFolder(folder);
+ }
+ for(String folder : IGNORED_FOLDERS) {
+ createFolder(folder);
+ }
+ }
+
void createFolder(String path) throws Exception {
final String [] parts = relPath(path).split("/");
Node n = session.getRootNode();
Modified: sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/FindPathsToWatchTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/FindPathsToWatchTest.java?rev=808453&r1=808452&r2=808453&view=diff
==============================================================================
--- sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/FindPathsToWatchTest.java (original)
+++ sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/FindPathsToWatchTest.java Thu Aug 27 15:19:08 2009
@@ -30,6 +30,8 @@
*/
public class FindPathsToWatchTest extends RepositoryTestBase {
+ public static final long TIMEOUT = 5000L;
+
SlingRepository repo;
Session session;
private EventHelper eventHelper;
@@ -57,6 +59,8 @@
session.logout();
eventHelper = null;
contentHelper = null;
+ installer.deactivate(MiscUtil.getMockComponentContext());
+ MiscUtil.waitForInstallerThread(installer, TIMEOUT);
}
private boolean isWatched(String path, Collection<WatchedFolder> wfList) {
@@ -67,7 +71,7 @@
}
return false;
}
-
+
public void testInitialFind() throws Exception {
final Collection<WatchedFolder> wf = MiscUtil.getWatchedFolders(installer);
assertEquals("activate() must find all watched folders", contentHelper.WATCHED_FOLDERS.length, wf.size());
@@ -94,8 +98,7 @@
// Create folder, wait for observation event and check that
// it is detected
contentHelper.createFolder(newPath);
- eventHelper.waitForEvents(5000L);
- MiscUtil.waitForCycles(installer, 2, 5000L);
+ MiscUtil.waitAfterContentChanges(eventHelper, installer);
if(newPath.contains("NOT")) {
assertFalse(newPath + " must not be watched after test", isWatched(newPath,
@@ -111,10 +114,10 @@
final int nBefore = MiscUtil.getWatchedFolders(installer).size();
contentHelper.delete(folder);
eventHelper.waitForEvents(5000L);
- MiscUtil.waitForCycles(installer, 2, 5000L);
+ MiscUtil.waitAfterContentChanges(eventHelper, installer);
assertFalse(folder + " must not be watched anymore after deleting", isWatched(folder,
MiscUtil.getWatchedFolders(installer)));
- assertEquals("Expecting only one WatchedFolder to be deleted", nBefore - 1,
+ assertEquals("Expecting only one WatchedFolder to be deleted", nBefore - 1,
MiscUtil.getWatchedFolders(installer).size());
}
@@ -122,8 +125,7 @@
final Collection<WatchedFolder> wf = MiscUtil.getWatchedFolders(installer);
assertEquals("activate() must find all watched folders", contentHelper.WATCHED_FOLDERS.length, wf.size());
contentHelper.cleanupContent();
- eventHelper.waitForEvents(5000L);
- MiscUtil.waitForCycles(installer, 2, 5000L);
+ MiscUtil.waitAfterContentChanges(eventHelper, installer);
assertEquals("After deleting content, no more folders must be watched", 0, wf.size());
}
}
\ No newline at end of file
Modified: sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/MiscUtil.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/MiscUtil.java?rev=808453&r1=808452&r2=808453&view=diff
==============================================================================
--- sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/MiscUtil.java (original)
+++ sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/MiscUtil.java Thu Aug 27 15:19:08 2009
@@ -133,13 +133,11 @@
return cc;
}
- static void waitForCycles(JcrInstaller installer, int nCycles, long timeoutMsec) throws Exception {
- final Field f = installer.getClass().getDeclaredField("cyclesCount");
- f.setAccessible(true);
- final int endCycles = ((Integer)f.get(installer)).intValue() + nCycles;
+ static private void waitForCycles(JcrInstaller installer, int nCycles, long timeoutMsec) throws Exception {
+ final long endCycles = installer.getCounters()[JcrInstaller.RUN_LOOP_COUNTER];
final long endTime = System.currentTimeMillis() + timeoutMsec;
while(System.currentTimeMillis() < endTime) {
- if(((Integer)f.get(installer)).intValue() > endCycles) {
+ if(installer.getCounters()[JcrInstaller.RUN_LOOP_COUNTER] > endCycles) {
return;
}
}
@@ -153,4 +151,25 @@
f.setAccessible(true);
return (Collection<WatchedFolder>)f.get(installer);
}
+
+ /** Wait long enough for all changes in content to be processed by JcrInstaller */
+ static void waitAfterContentChanges(EventHelper eventHelper, JcrInstaller installer) throws Exception {
+ // First wait for all JCR events to be delivered
+ eventHelper.waitForEvents(5000L);
+ // RescanTimer causes a SCAN_DELAY_MSEC wait after JCR events are received
+ Thread.sleep(RescanTimer.SCAN_DELAY_MSEC * 2);
+ // And wait for 2 complete JcrInstaller run cycles, to be on the safe side
+ MiscUtil.waitForCycles(installer, 3, 5000L);
+ }
+
+ /** Wait until installer thread exits */
+ static void waitForInstallerThread(JcrInstaller installer, long timeoutMsec) throws Exception {
+ final long endTime = System.currentTimeMillis() + timeoutMsec;
+ while(System.currentTimeMillis() < endTime) {
+ if(installer.getCounters()[JcrInstaller.RUN_LOOP_COUNTER] == -1) {
+ return;
+ }
+ }
+ throw new Exception("JcrInstaller thread did not signal its end (timeout=" + timeoutMsec + " msec)");
+ }
}
Modified: sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/ResourceDetectionTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/ResourceDetectionTest.java?rev=808453&r1=808452&r2=808453&view=diff
==============================================================================
--- sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/ResourceDetectionTest.java (original)
+++ sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/ResourceDetectionTest.java Thu Aug 27 15:19:08 2009
@@ -58,6 +58,8 @@
session.logout();
eventHelper = null;
contentHelper = null;
+ installer.deactivate(MiscUtil.getMockComponentContext());
+ MiscUtil.waitForInstallerThread(installer, TIMEOUT);
}
private void assertRegisteredPaths(String [] paths) {
@@ -106,8 +108,7 @@
for(String path : paths) {
contentHelper.createOrUpdateFile(path);
}
- eventHelper.waitForEvents(TIMEOUT);
- MiscUtil.waitForCycles(installer, 2, TIMEOUT);
+ MiscUtil.waitAfterContentChanges(eventHelper, installer);
assertRegisteredPaths(paths);
}
@@ -125,8 +126,7 @@
contentHelper.createConfig(path, null);
}
- eventHelper.waitForEvents(TIMEOUT);
- MiscUtil.waitForCycles(installer, 2, TIMEOUT);
+ MiscUtil.waitAfterContentChanges(eventHelper, installer);
assertRegisteredPaths(paths);
}
@@ -140,8 +140,7 @@
final int toRemove = 1;
contentHelper.delete(contentHelper.FAKE_RESOURCES[toRemove]);
contentHelper.delete(contentHelper.FAKE_CONFIGS[toRemove]);
- eventHelper.waitForEvents(TIMEOUT);
- MiscUtil.waitForCycles(installer, 2, TIMEOUT);
+ MiscUtil.waitAfterContentChanges(eventHelper, installer);
for(int i=0; i < contentHelper.FAKE_RESOURCES.length; i++) {
assertRegistered(contentHelper.FAKE_RESOURCES[i], i != toRemove);
@@ -184,7 +183,7 @@
// Restart JcrInstaller and verify that all remaining resources are re-registered
installer.activate(cc);
- MiscUtil.waitForCycles(installer, 2, TIMEOUT);
+ MiscUtil.waitAfterContentChanges(eventHelper, installer);
for(int i=0; i < contentHelper.FAKE_RESOURCES.length; i++) {
final String path = contentHelper.FAKE_RESOURCES[i];
@@ -213,8 +212,7 @@
// Removing a folder, all resources that it contains must be unregistered
contentHelper.delete("/libs");
- eventHelper.waitForEvents(TIMEOUT);
- MiscUtil.waitForCycles(installer, 2, TIMEOUT);
+ MiscUtil.waitAfterContentChanges(eventHelper, installer);
for(String path : contentHelper.FAKE_RESOURCES) {
assertRegistered(path, !path.startsWith("/libs"));
}
@@ -232,16 +230,14 @@
int nCalls = osgiInstaller.getRecordedCalls().size();
((Node)session.getItem(path + "/jcr:content")).setProperty("jcr:mimeType", "application/" + getClass().getName());
session.save();
- eventHelper.waitForEvents(TIMEOUT);
- MiscUtil.waitForCycles(installer, 2, TIMEOUT);
+ MiscUtil.waitAfterContentChanges(eventHelper, installer);
assertEquals("Expected no OsgiInstaller calls for no-impact file change",
nCalls, osgiInstaller.getRecordedCalls().size());
// Make a content change -> resource must be re-registered
osgiInstaller.clearRecordedCalls();
contentHelper.createOrUpdateFile(path, null, System.currentTimeMillis());
- eventHelper.waitForEvents(TIMEOUT);
- MiscUtil.waitForCycles(installer, 2, TIMEOUT);
+ MiscUtil.waitAfterContentChanges(eventHelper, installer);
assertEquals("Expected one OsgiInstaller call for file content change",
1, osgiInstaller.getRecordedCalls().size());
assertRecordedCall("add", path);
@@ -256,24 +252,21 @@
final String value = "value" + System.currentTimeMillis();
((Node)session.getItem(path)).setProperty(key, value);
session.save();
- eventHelper.waitForEvents(TIMEOUT);
- MiscUtil.waitForCycles(installer, 2, TIMEOUT);
+ MiscUtil.waitAfterContentChanges(eventHelper, installer);
// Make a change that does not influence the configs's digest,
// and verify that no OSGi registrations result
int nCalls = osgiInstaller.getRecordedCalls().size();
((Node)session.getItem(path)).setProperty(key, value);
session.save();
- eventHelper.waitForEvents(TIMEOUT);
- MiscUtil.waitForCycles(installer, 2, TIMEOUT);
+ MiscUtil.waitAfterContentChanges(eventHelper, installer);
assertEquals("Expected no OsgiInstaller calls for no-impact config change",
nCalls, osgiInstaller.getRecordedCalls().size());
// Make a content change -> resource must be re-registered
osgiInstaller.clearRecordedCalls();
((Node)session.getItem(path)).setProperty(key, value + "-changed");
- eventHelper.waitForEvents(TIMEOUT);
- MiscUtil.waitForCycles(installer, 2, TIMEOUT);
+ MiscUtil.waitAfterContentChanges(eventHelper, installer);
assertEquals("Expected one OsgiInstaller call for config content change",
1, osgiInstaller.getRecordedCalls().size());
assertRecordedCall("add", path);
Added: sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/ScanningLoopTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/ScanningLoopTest.java?rev=808453&view=auto
==============================================================================
--- sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/ScanningLoopTest.java (added)
+++ sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/ScanningLoopTest.java Thu Aug 27 15:19:08 2009
@@ -0,0 +1,138 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.jcr.jcrinstall.impl;
+
+import javax.jcr.Session;
+
+import org.apache.sling.commons.testing.jcr.RepositoryTestBase;
+import org.apache.sling.jcr.api.SlingRepository;
+import org.junit.Test;
+
+/** Verify that JcrInstaller scans folders only when needed */
+public class ScanningLoopTest extends RepositoryTestBase {
+ public static final long TIMEOUT = 5000L;
+
+ private JcrInstaller installer;
+ private SlingRepository repository;
+ private MockOsgiInstaller osgiInstaller;
+ private ContentHelper contentHelper;
+ private Session session;
+ private EventHelper eventHelper;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ repository = getRepository();
+ osgiInstaller = new MockOsgiInstaller();
+ installer = MiscUtil.getJcrInstaller(repository, osgiInstaller);
+ session = repository.loginAdministrative(repository.getDefaultWorkspace());
+ eventHelper = new EventHelper(session);
+ contentHelper = new ContentHelper(session);
+ contentHelper.setupFolders();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ installer.deactivate(MiscUtil.getMockComponentContext());
+ MiscUtil.waitForInstallerThread(installer, TIMEOUT);
+ installer = null;
+ contentHelper.cleanupContent();
+ if(session != null) {
+ session.logout();
+ session = null;
+ }
+ }
+
+ private void assertCounter(int index, long value) {
+ assertEquals("Counter " + index, value, installer.getCounters()[index]);
+ }
+
+ private void assertIdle() throws Exception {
+ final long sf = installer.getCounters()[JcrInstaller.SCAN_FOLDERS_COUNTER];
+ final long uc = installer.getCounters()[JcrInstaller.UPDATE_FOLDERS_LIST_COUNTER];
+ Thread.sleep(JcrInstaller.RUN_LOOP_DELAY_MSEC * 2);
+ assertCounter(JcrInstaller.SCAN_FOLDERS_COUNTER, sf);
+ assertCounter(JcrInstaller.UPDATE_FOLDERS_LIST_COUNTER, uc);
+ }
+
+ private void assertEvents(String info, long oldCount, int counterIndex) {
+ final long newCount = installer.getCounters()[counterIndex];
+ assertTrue(info + " (old=" + oldCount + ", new=" + newCount + ")", newCount > oldCount);
+ }
+
+ @Test
+ public void testIdleState() throws Exception {
+ Thread.sleep(JcrInstaller.RUN_LOOP_DELAY_MSEC * 2);
+ assertIdle();
+ }
+
+ @Test
+ public void testAddBundle() throws Exception {
+ contentHelper.createOrUpdateFile(contentHelper.FAKE_RESOURCES[0]);
+ eventHelper.waitForEvents(TIMEOUT);
+ Thread.sleep(JcrInstaller.RUN_LOOP_DELAY_MSEC * 2);
+ assertIdle();
+ }
+
+ public void testAddContentOutside() throws Exception {
+ final long sf = installer.getCounters()[JcrInstaller.SCAN_FOLDERS_COUNTER];
+ final long uc = installer.getCounters()[JcrInstaller.UPDATE_FOLDERS_LIST_COUNTER];
+
+ contentHelper.createOrUpdateFile("/" + System.currentTimeMillis());
+ eventHelper.waitForEvents(TIMEOUT);
+ Thread.sleep(JcrInstaller.RUN_LOOP_DELAY_MSEC * 2);
+
+ // Adding a file outside /libs or /apps must not "wake up" the scan loop
+ assertCounter(JcrInstaller.SCAN_FOLDERS_COUNTER, sf);
+ assertCounter(JcrInstaller.UPDATE_FOLDERS_LIST_COUNTER, uc);
+ }
+
+ public void testDeleteFile() throws Exception {
+ contentHelper.setupContent();
+ eventHelper.waitForEvents(TIMEOUT);
+ Thread.sleep(JcrInstaller.RUN_LOOP_DELAY_MSEC * 2);
+ assertIdle();
+
+ final long sf = installer.getCounters()[JcrInstaller.SCAN_FOLDERS_COUNTER];
+ contentHelper.delete(contentHelper.FAKE_RESOURCES[0]);
+ eventHelper.waitForEvents(TIMEOUT);
+ Thread.sleep(JcrInstaller.RUN_LOOP_DELAY_MSEC * 2);
+ assertEvents("Expected at least one folder scan event",
+ sf, JcrInstaller.SCAN_FOLDERS_COUNTER);
+
+ assertIdle();
+ }
+
+ public void testDeleteLibsFolder() throws Exception {
+ contentHelper.setupContent();
+ eventHelper.waitForEvents(TIMEOUT);
+ Thread.sleep(JcrInstaller.RUN_LOOP_DELAY_MSEC * 2);
+ assertIdle();
+
+ final long uc = installer.getCounters()[JcrInstaller.UPDATE_FOLDERS_LIST_COUNTER];
+ contentHelper.delete("/libs");
+ eventHelper.waitForEvents(TIMEOUT);
+ Thread.sleep(JcrInstaller.RUN_LOOP_DELAY_MSEC * 2);
+ assertEvents("Expected at least one folders list update event",
+ uc, JcrInstaller.UPDATE_FOLDERS_LIST_COUNTER);
+
+ assertIdle();
+ }
+}
\ No newline at end of file
Propchange: sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/ScanningLoopTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/ScanningLoopTest.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision Rev URL