Skip to content

Commit f7a7a34

Browse files
committed
Rename overflow auto-handling approach constants
1 parent 4beb950 commit f7a7a34

File tree

4 files changed

+124
-79
lines changed

4 files changed

+124
-79
lines changed
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/*
2+
* BSD 2-Clause License
3+
*
4+
* Copyright (c) 2023, Swat.engineering
5+
*
6+
* Redistribution and use in source and binary forms, with or without
7+
* modification, are permitted provided that the following conditions are met:
8+
*
9+
* 1. Redistributions of source code must retain the above copyright notice, this
10+
* list of conditions and the following disclaimer.
11+
*
12+
* 2. Redistributions in binary form must reproduce the above copyright notice,
13+
* this list of conditions and the following disclaimer in the documentation
14+
* and/or other materials provided with the distribution.
15+
*
16+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
20+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26+
*/
27+
package engineering.swat.watch;
28+
29+
/**
30+
* Constants to indicate for which regular files/directories in the scope of the
31+
* watch an <i>approximation</i> of synthetic events (of kinds
32+
* {@link WatchEvent.Kind#CREATED}, {@link WatchEvent.Kind#MODIFIED}, and/or
33+
* {@link WatchEvent.Kind#DELETED}) should be issued when an overflow event
34+
* happens. These synthetic events, as well as the overflow event itself, are
35+
* subsequently passed to the user-defined event handler of the watch.
36+
* Typically, the user-defined event handler can ignore the original overflow
37+
* event (i.e., handling the synthetic events is sufficient to address the
38+
* overflow issue), but it doesn't have to (e.g., it may carry out additional
39+
* overflow bookkeeping).
40+
*/
41+
public enum OnOverflow {
42+
43+
/**
44+
* Synthetic events are issued for <b>no regular files/directories</b> in
45+
* the scope of the watch. Thus, the user-defined event handler is fully
46+
* responsible to handle overflow events.
47+
*/
48+
NONE,
49+
50+
/**
51+
* <p>
52+
* Synthetic events of kinds {@link WatchEvent.Kind#CREATED} and
53+
* {@link WatchEvent.Kind#MODIFIED}, but not
54+
* {@link WatchEvent.Kind#DELETED}, are issued for all regular
55+
* files/directories in the scope of the watch. Specifically, when an
56+
* overflow event happens:
57+
*
58+
* <ul>
59+
* <li>CREATED events are issued for all regular files/directories
60+
* (overapproximation).
61+
* <li>MODIFIED events are issued for all non-empty, regular files
62+
* (overapproximation) but for no directories (underapproximation).
63+
* <li>DELETED events are issued for no regular files/directories
64+
* (underapproximation).
65+
* </ul>
66+
*
67+
* <p>
68+
* This approach is relatively cheap in terms of memory usage (cf.
69+
* {@link #DIRTY}), but it results in a large over/underapproximation of the
70+
* actual events (cf. DIRTY).
71+
*/
72+
ALL,
73+
74+
75+
/**
76+
* <p>
77+
* Synthetic events of kinds {@link WatchEvent.Kind#CREATED},
78+
* {@link WatchEvent.Kind#MODIFIED}, and {@link WatchEvent.Kind#DELETED} are
79+
* issued for dirty regular files/directories in the scope of the watch, as
80+
* determined using <i>last-modified-times</i>. Specifically, when an
81+
* overflow event happens:
82+
*
83+
* <ul>
84+
* <li>CREATED events are issued for all regular files/directories when the
85+
* previous last-modified-time is unknown, but the current
86+
* last-modified-time is known (i.e., the file started existing).
87+
* <li>MODIFIED events are issued for all regular files/directories when the
88+
* previous last-modified-time is before the current last-modified-time.
89+
* <li>DELETED events are issued for all regular files/directories when the
90+
* previous last-modified-time is known, but the current
91+
* last-modified-time is unknown (i.e., the file stopped existing).
92+
* </ul>
93+
*
94+
* <p>
95+
* To keep track of last-modified-times, an internal <i>index</i> is
96+
* populated with last-modified-times of all regular files/directories in
97+
* the scope of the watch when the watch is started. Each time when any
98+
* event happens, the index is updated accordingly, so when an overflow
99+
* event happens, last-modified-times can be compared as described above.
100+
*
101+
* <p>
102+
* This approach results in a small overapproximation (cf. {@link #ALL}),
103+
* but it is relatively expensive in terms of memory usage (cf. ALL), as the
104+
* watch needs to keep track of last-modified-times.
105+
*/
106+
DIRTY
107+
}

src/main/java/engineering/swat/watch/OverflowPolicy.java

Lines changed: 0 additions & 65 deletions
This file was deleted.

src/main/java/engineering/swat/watch/Watcher.java

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public class Watcher {
5555
private final Logger logger = LogManager.getLogger();
5656
private final Path path;
5757
private final WatchScope scope;
58-
private volatile OverflowPolicy overflowPolicy = OverflowPolicy.MEMORYLESS_RESCANS;
58+
private volatile OnOverflow approximateOnOverflow = OnOverflow.ALL;
5959
private volatile Executor executor = CompletableFuture::runAsync;
6060

6161
private static final BiConsumer<EventHandlingWatch, WatchEvent> EMPTY_HANDLER = (w, e) -> {};
@@ -149,15 +149,18 @@ public Watcher withExecutor(Executor callbackHandler) {
149149
}
150150

151151
/**
152-
* Optionally configure the overflow policy of this watcher to automatically
153-
* handle overflow events. If not defined before this watcher is started,
154-
* the {@link engineering.swat.watch.OverflowPolicy#MEMORYLESS_RESCANS}
155-
* policy will be used.
156-
* @param overflowPolicy The overflow policy to use
152+
* Optionally configure which regular files/directories in the scope of the
153+
* watch an <i>approximation</i> of synthetic events (of kinds
154+
* {@link WatchEvent.Kind#CREATED}, {@link WatchEvent.Kind#MODIFIED}, and/or
155+
* {@link WatchEvent.Kind#DELETED}) should be issued when an overflow event
156+
* happens. If not defined before this watcher is started, the
157+
* {@link engineering.swat.watch.OnOverflow#ALL} approach will be used.
158+
* @param whichFiles Constant to indicate for which regular
159+
* files/directories to approximate
157160
* @return This watcher for optional method chaining
158161
*/
159-
public Watcher withOverflowPolicy(OverflowPolicy overflowPolicy) {
160-
this.overflowPolicy = overflowPolicy;
162+
public Watcher approximate(OnOverflow whichFiles) {
163+
this.approximateOnOverflow = whichFiles;
161164
return this;
162165
}
163166

@@ -172,7 +175,7 @@ public ActiveWatch start() throws IOException {
172175
throw new IllegalStateException("There is no onEvent handler defined");
173176
}
174177

175-
var h = applyOverflowPolicy();
178+
var h = applyApproximateOnOverflow();
176179

177180
switch (scope) {
178181
case PATH_AND_CHILDREN: {
@@ -204,11 +207,11 @@ public ActiveWatch start() throws IOException {
204207
}
205208
}
206209

207-
private BiConsumer<EventHandlingWatch, WatchEvent> applyOverflowPolicy() {
208-
switch (overflowPolicy) {
209-
case NO_RESCANS:
210+
private BiConsumer<EventHandlingWatch, WatchEvent> applyApproximateOnOverflow() {
211+
switch (approximateOnOverflow) {
212+
case NONE:
210213
return eventHandler;
211-
case MEMORYLESS_RESCANS:
214+
case ALL:
212215
return new MemorylessRescanner(executor).andThen(eventHandler);
213216
default:
214217
throw new UnsupportedOperationException("No event handler has been defined yet for this overflow policy");

src/test/java/engineering/swat/watch/SingleDirectoryTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ void memorylessRescanOnOverflow() throws IOException, InterruptedException {
132132
var nModified = new AtomicInteger();
133133
var nOverflow = new AtomicInteger();
134134
var watchConfig = Watcher.watch(directory, WatchScope.PATH_AND_CHILDREN)
135-
.withOverflowPolicy(OverflowPolicy.MEMORYLESS_RESCANS)
135+
.approximate(OnOverflow.ALL)
136136
.on(e -> {
137137
switch (e.getKind()) {
138138
case CREATED:

0 commit comments

Comments
 (0)