Issue #5086 Changes after review

Signed-off-by: Jan Bartel <janb@webtide.com>
This commit is contained in:
Jan Bartel 2020-12-01 22:05:33 +01:00
parent 90e48ba0b5
commit 31cc298987
4 changed files with 80 additions and 79 deletions

View File

@ -54,7 +54,6 @@ public abstract class ScanningAppProvider extends ContainerLifeCycle implements
private DeploymentManager _deploymentManager;
protected FilenameFilter _filenameFilter;
private final List<Resource> _monitored = new CopyOnWriteArrayList<>();
private boolean _recursive = false;
private int _scanInterval = 10;
private Scanner _scanner;
@ -236,12 +235,6 @@ public abstract class ScanningAppProvider extends ContainerLifeCycle implements
return _scanInterval;
}
@ManagedAttribute("recursive scanning supported")
public boolean isRecursive()
{
return _recursive;
}
@Override
public void setDeploymentManager(DeploymentManager deploymentManager)
{
@ -294,11 +287,6 @@ public abstract class ScanningAppProvider extends ContainerLifeCycle implements
}
}
protected void setRecursive(boolean recursive)
{
_recursive = recursive;
}
public void setScanInterval(int scanInterval)
{
_scanInterval = scanInterval;
@ -311,7 +299,7 @@ public abstract class ScanningAppProvider extends ContainerLifeCycle implements
getMonitoredResources().stream().map((r) -> r.getURI().toASCIIString())
.collect(Collectors.joining(", ", "[", "]"))
);
_scanner.scan();
_scanner.nudge();
}
@Override

View File

@ -35,14 +35,15 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Predicate;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler;
import org.eclipse.jetty.util.thread.Scheduler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -67,15 +68,15 @@ public class Scanner extends AbstractLifeCycle
private static int __scannerId = 0;
private int _scanInterval;
private AtomicInteger _scanCount = new AtomicInteger(0);
private final AtomicInteger _scanCount = new AtomicInteger(0);
private final List<Listener> _listeners = new CopyOnWriteArrayList<>();
private Map<String, MetaData> _prevScan;
private FilenameFilter _filter;
private final Map<Path, IncludeExcludeSet<PathMatcher, Path>> _scannables = new ConcurrentHashMap<>();
private boolean _reportExisting = true;
private boolean _reportDirs = true;
private Timer _timer;
private TimerTask _task;
private Scheduler.Task _task;
private ScheduledExecutorScheduler _scheduler;
private int _scanDepth = DEFAULT_SCAN_DEPTH;
public enum Status
@ -114,7 +115,7 @@ public class Scanner extends AbstractLifeCycle
* Metadata about a file: Last modified time, file size and
* last file status (ADDED, CHANGED, DELETED, STABLE)
*/
static class MetaData
private static class MetaData
{
final long _lastModified;
final long _size;
@ -125,11 +126,6 @@ public class Scanner extends AbstractLifeCycle
_lastModified = lastModified;
_size = size;
}
public void setStatus(Status status)
{
_status = status;
}
@Override
public int hashCode()
@ -148,6 +144,16 @@ public class Scanner extends AbstractLifeCycle
return "[lm=" + _lastModified + ",sz=" + _size + ",s=" + _status + "]";
}
}
private class ScanTask implements Runnable
{
@Override
public void run()
{
scan();
schedule();
}
}
/**
* Visitor
@ -183,9 +189,7 @@ public class Scanner extends AbstractLifeCycle
if (rootIncludesExcludes != null && !rootIncludesExcludes.isEmpty())
{
//accepted if not explicitly excluded and either is explicitly included or there are no explicit inclusions
Boolean result = rootIncludesExcludes.test(dir);
if (Boolean.TRUE == result)
accepted = true;
accepted = rootIncludesExcludes.test(dir);
}
else
{
@ -217,9 +221,7 @@ public class Scanner extends AbstractLifeCycle
if (rootIncludesExcludes != null && !rootIncludesExcludes.isEmpty())
{
//accepted if not explicitly excluded and either is explicitly included or there are no explicit inclusions
Boolean result = rootIncludesExcludes.test(file);
if (Boolean.TRUE == result)
accepted = true;
accepted = rootIncludesExcludes.test(file);
}
else if (_filter == null || _filter.accept(f.getParentFile(), f.getName()))
accepted = true;
@ -259,7 +261,6 @@ public class Scanner extends AbstractLifeCycle
/**
* Notification of exact file changes in the last scan.
*
*/
public interface DiscreteListener extends Listener
{
@ -272,7 +273,6 @@ public class Scanner extends AbstractLifeCycle
/**
* Notification of files that changed in the last scan.
*
*/
public interface BulkListener extends Listener
{
@ -312,12 +312,11 @@ public class Scanner extends AbstractLifeCycle
* @param scanInterval pause between scans in seconds, or 0 for no scan after the initial scan.
*/
public void setScanInterval(int scanInterval)
{
{
if (isRunning())
throw new IllegalStateException("Scanner started");
_scanInterval = scanInterval;
schedule();
}
public void setScanDirs(List<File> dirs)
@ -506,7 +505,7 @@ public class Scanner extends AbstractLifeCycle
* Start the scanning action.
*/
@Override
public void doStart()
public void doStart() throws Exception
{
if (LOG.isDebugEnabled())
LOG.debug("Scanner start: rprtExists={}, depth={}, rprtDirs={}, interval={}, filter={}, scannables={}",
@ -523,40 +522,21 @@ public class Scanner extends AbstractLifeCycle
//just register the list of existing files and only report changes
_prevScan = scanFiles();
}
//Create the scheduler and start it
_scheduler = new ScheduledExecutorScheduler("Scanner-" + __scannerId++, true, 1);
_scheduler.start();
//schedule the scan
schedule();
}
public TimerTask newTimerTask()
private void schedule()
{
return new TimerTask()
if (isRunning() && getScanInterval() > 0)
{
@Override
public void run()
{
scan();
}
};
}
public Timer newTimer()
{
return new Timer("Scanner-" + __scannerId++, true);
}
public void schedule()
{
if (isRunning())
{
if (_timer != null)
_timer.cancel();
if (_task != null)
_task.cancel();
if (getScanInterval() > 0)
{
_timer = newTimer();
_task = newTimerTask();
_timer.schedule(_task, 1010L * getScanInterval(), 1010L * getScanInterval());
}
_task = _scheduler.schedule(new ScanTask(), 1010L * getScanInterval(), TimeUnit.MILLISECONDS);
}
}
@ -566,12 +546,20 @@ public class Scanner extends AbstractLifeCycle
@Override
public void doStop()
{
if (_timer != null)
_timer.cancel();
try
{
if (_scheduler != null)
_scheduler.stop();
}
catch (Exception e)
{
LOG.warn("Error stopping scheduler", e);
}
if (_task != null)
_task.cancel();
_scheduler = null;
_task = null;
_timer = null;
}
/**
@ -604,10 +592,27 @@ public class Scanner extends AbstractLifeCycle
return false;
}
/**
* Hint to the scanner to perform a scan cycle as soon as possible.
* NOTE that the scan is not guaranteed to have happened by the
* time this method returns.
*/
public void nudge()
{
if (!isRunning())
throw new IllegalStateException("Scanner not running");
_scheduler.schedule(() ->
{
scan();
}, 0, TimeUnit.MILLISECONDS);
}
/**
* Perform a pass of the scanner and report changes
*/
public void scan()
void scan()
{
int cycle = _scanCount.incrementAndGet();
reportScanStart(cycle);
@ -620,7 +625,7 @@ public class Scanner extends AbstractLifeCycle
/**
* Scan all of the given paths.
*/
public Map<String, MetaData> scanFiles()
private Map<String, MetaData> scanFiles()
{
Map<String, MetaData> currentScan = new HashMap<>();
for (Path p : _scannables.keySet())

View File

@ -20,7 +20,6 @@ package org.eclipse.jetty.util.ssl;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.function.Consumer;
import org.eclipse.jetty.util.Scanner;
@ -122,8 +121,8 @@ public class KeyStoreScanner extends ContainerLifeCycle implements Scanner.Discr
if (LOG.isDebugEnabled())
LOG.debug("scanning");
_scanner.scan();
_scanner.scan();
_scanner.nudge();
_scanner.nudge();
}
@ManagedOperation(value = "Reload the SSL Keystore", impact = "ACTION")

View File

@ -26,6 +26,7 @@ import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
@ -129,6 +130,12 @@ public class ScannerTest
return ((Event)obj)._filename.equals(_filename) && ((Event)obj)._notification == _notification;
}
@Override
public int hashCode()
{
return Objects.hash(_filename, _notification);
}
@Override
public String toString()
{
@ -278,8 +285,10 @@ public class ScannerTest
scanner.scan();
scanner.scan(); //2 scans for file to be considered settled
assertThat(queue.size(), Matchers.equalTo(2));
for (Event e : queue)
List<Event> results = new ArrayList<>();
queue.drainTo(results);
assertThat(results.size(), Matchers.equalTo(2));
for (Event e : results)
{
assertTrue(e._filename.endsWith("ttt.txt") || e._filename.endsWith("xxx.txt"));
}
@ -295,7 +304,7 @@ public class ScannerTest
_scanner.scan();
_scanner.scan();
Event event = _queue.poll();
Event event = _queue.poll(5, TimeUnit.SECONDS);
assertNotNull(event, "Event should not be null");
assertEquals(_directory + "/a0", event._filename);
assertEquals(Notification.ADDED, event._notification);
@ -325,7 +334,7 @@ public class ScannerTest
Event a3 = new Event(_directory + "/a3", Notification.REMOVED);
assertThat(actualEvents, Matchers.containsInAnyOrder(a1, a3));
assertTrue(_queue.isEmpty());
// Now a2 is stable
_scanner.scan();
event = _queue.poll();
@ -366,7 +375,7 @@ public class ScannerTest
// delete a1 and a2
delete("a1");
delete("a2");
//Immediate notification of deletes.
_scanner.scan();
a1 = new Event(_directory + "/a1", Notification.REMOVED);
@ -376,7 +385,7 @@ public class ScannerTest
assertEquals(2, actualEvents.size());
assertThat(actualEvents, Matchers.containsInAnyOrder(a1, a2));
assertTrue(_queue.isEmpty());
// recreate a2
touch("a2");
@ -389,7 +398,7 @@ public class ScannerTest
//Now a2 is reported as ADDED.
_scanner.scan();
event = _queue.poll();
assertTrue(event != null);
assertNotNull(event);
assertEquals(_directory + "/a2", event._filename);
assertEquals(Notification.ADDED, event._notification);
assertTrue(_queue.isEmpty());