Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/jdk17u
Path: blob/master/test/jdk/java/nio/file/WatchService/LotsOfEvents.java
66645 views
1
/*
2
* Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation.
8
*
9
* This code is distributed in the hope that it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12
* version 2 for more details (a copy is included in the LICENSE file that
13
* accompanied this code).
14
*
15
* You should have received a copy of the GNU General Public License version
16
* 2 along with this work; if not, write to the Free Software Foundation,
17
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
*
19
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20
* or visit www.oracle.com if you need additional information or have any
21
* questions.
22
*/
23
24
/* @test
25
* @bug 6907760 6929532 8174819
26
* @summary Tests WatchService behavior when lots of events are pending (use -Dseed=X to set PRNG seed)
27
* @library ..
28
* @library /test/lib
29
* @build jdk.test.lib.RandomFactory
30
* @run main/timeout=180 LotsOfEvents
31
* @key randomness
32
*/
33
34
import java.io.IOException;
35
import java.io.OutputStream;
36
import java.nio.file.*;
37
import static java.nio.file.StandardWatchEventKinds.*;
38
import java.util.*;
39
import java.util.concurrent.TimeUnit;
40
import java.util.stream.Collectors;
41
42
import jdk.test.lib.RandomFactory;
43
44
public class LotsOfEvents {
45
46
private static final Random RAND = RandomFactory.getRandom();
47
48
public static void main(String[] args) throws Exception {
49
Path dir = TestUtil.createTemporaryDirectory();
50
try {
51
testOverflowEvent(dir);
52
testModifyEventsQueuing(dir);
53
} finally {
54
TestUtil.removeAll(dir);
55
}
56
}
57
58
/**
59
* Tests that OVERFLOW events are not retreived with other events.
60
*/
61
static void testOverflowEvent(Path dir)
62
throws IOException, InterruptedException
63
{
64
try (WatchService watcher = dir.getFileSystem().newWatchService()) {
65
dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE);
66
67
// create a lot of files
68
int n = 1024;
69
Path[] files = new Path[n];
70
for (int i=0; i<n; i++) {
71
files[i] = Files.createFile(dir.resolve("foo" + i));
72
}
73
74
// give time for events to accumulate (improve chance of overflow)
75
Thread.sleep(1000);
76
77
// check that we see the create events (or overflow)
78
drainAndCheckOverflowEvents(dir, watcher, ENTRY_CREATE, n);
79
80
// delete the files
81
for (int i=0; i<n; i++) {
82
Files.delete(files[i]);
83
}
84
85
// give time for events to accumulate (improve chance of overflow)
86
Thread.sleep(1000);
87
88
// check that we see the delete events (or overflow)
89
drainAndCheckOverflowEvents(dir, watcher, ENTRY_DELETE, n);
90
}
91
}
92
93
static void drainAndCheckOverflowEvents(Path dir,
94
WatchService watcher,
95
WatchEvent.Kind<?> expectedKind,
96
int count)
97
throws IOException, InterruptedException
98
{
99
// wait for key to be signalled - the timeout is long to allow for
100
// polling implementations
101
WatchKey key = watcher.poll(15, TimeUnit.SECONDS);
102
if (key != null && count == 0)
103
throw new RuntimeException("Key was signalled (unexpected)");
104
if (key == null && count > 0)
105
throw new RuntimeException("Key not signalled (unexpected)");
106
107
int nread = 0;
108
boolean gotOverflow = false;
109
while (key != null) {
110
List<WatchEvent<?>> events = key.pollEvents();
111
System.out.println("Polling retrieved " + events.size() + " event(s)");
112
for (WatchEvent<?> event: events) {
113
WatchEvent.Kind<?> kind = event.kind();
114
if (kind == expectedKind) {
115
// expected event kind
116
if (++nread > count)
117
throw new RuntimeException("More events than expected!!");
118
} else if (kind == OVERFLOW) {
119
// overflow event should not be retrieved with other events
120
if (events.size() > 1)
121
throw new RuntimeException("Overflow retrieved with other events");
122
gotOverflow = true;
123
} else {
124
throw new RuntimeException("Unexpected event '" + kind + "'");
125
}
126
}
127
if (!key.reset())
128
throw new RuntimeException("Key is no longer valid");
129
key = watcher.poll(15, TimeUnit.SECONDS);
130
}
131
132
// check that all expected events were received or there was an overflow
133
if (nread < count && !gotOverflow) {
134
System.err.printf("Test directory %s contains %d files%n",
135
dir, Files.list(dir).count());
136
137
// the additional polling here is just for diagnostics and doesn't
138
// change the test result (which is a failed test)
139
long timeBeforePoll = System.nanoTime();
140
key = watcher.poll(15, TimeUnit.SECONDS);
141
long timeAfterPoll = System.nanoTime();
142
if (key == null) {
143
System.err.println("key still null after extra polling");
144
} else {
145
List<WatchEvent<?>> events = key.pollEvents();
146
System.err.printf("Retrieved key with %d events after %d ns%n",
147
events.size(), timeAfterPoll - timeBeforePoll);
148
// count for each kind of event
149
Map<WatchEvent.Kind, Long> countPerEventType = events.stream()
150
.collect(Collectors.groupingBy(WatchEvent::kind, Collectors.counting()));
151
countPerEventType.forEach((kind, num)
152
-> System.err.println(num + " events of type " + kind));
153
}
154
155
throw new RuntimeException("Insufficient "
156
+ expectedKind.name() + " events: expected "
157
+ count + ", received " + nread);
158
}
159
}
160
161
/**
162
* Tests that check that ENTRY_MODIFY events are queued efficiently
163
*/
164
static void testModifyEventsQueuing(Path dir)
165
throws IOException, InterruptedException
166
{
167
// this test uses a random number of files
168
final int nfiles = 5 + RAND.nextInt(10);
169
DirectoryEntry[] entries = new DirectoryEntry[nfiles];
170
for (int i=0; i<nfiles; i++) {
171
entries[i] = new DirectoryEntry(dir.resolve("foo" + i));
172
173
// "some" of the files exist, some do not.
174
entries[i].deleteIfExists();
175
if (RAND.nextBoolean())
176
entries[i].create();
177
}
178
179
try (WatchService watcher = dir.getFileSystem().newWatchService()) {
180
dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
181
182
// do several rounds of noise and test
183
for (int round=0; round<10; round++) {
184
185
// make some noise!!!
186
for (int i=0; i<100; i++) {
187
DirectoryEntry entry = entries[RAND.nextInt(nfiles)];
188
int action = RAND.nextInt(10);
189
switch (action) {
190
case 0 : entry.create(); break;
191
case 1 : entry.deleteIfExists(); break;
192
default: entry.modifyIfExists();
193
}
194
}
195
196
// process events and ensure that we don't get repeated modify
197
// events for the same file.
198
WatchKey key = watcher.poll(15, TimeUnit.SECONDS);
199
while (key != null) {
200
Set<Path> modified = new HashSet<>();
201
for (WatchEvent<?> event: key.pollEvents()) {
202
WatchEvent.Kind<?> kind = event.kind();
203
Path file = (kind == OVERFLOW) ? null : (Path)event.context();
204
if (kind == ENTRY_MODIFY) {
205
boolean added = modified.add(file);
206
if (!added) {
207
throw new RuntimeException(
208
"ENTRY_MODIFY events not queued efficiently");
209
}
210
} else {
211
if (file != null) modified.remove(file);
212
}
213
}
214
if (!key.reset())
215
throw new RuntimeException("Key is no longer valid");
216
key = watcher.poll(2, TimeUnit.SECONDS);
217
}
218
}
219
}
220
}
221
222
static class DirectoryEntry {
223
private final Path file;
224
DirectoryEntry(Path file) {
225
this.file = file;
226
}
227
void create() throws IOException {
228
if (Files.notExists(file))
229
Files.createFile(file);
230
231
}
232
void deleteIfExists() throws IOException {
233
Files.deleteIfExists(file);
234
}
235
void modifyIfExists() throws IOException {
236
if (Files.exists(file)) {
237
try (OutputStream out = Files.newOutputStream(file, StandardOpenOption.APPEND)) {
238
out.write("message".getBytes());
239
}
240
}
241
}
242
}
243
244
}
245
246