Path: blob/master/test/jdk/java/nio/file/WatchService/LotsOfEvents.java
41153 views
/*1* Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/* @test24* @bug 6907760 692953225* @summary Tests WatchService behavior when lots of events are pending (use -Dseed=X to set PRNG seed)26* @library ..27* @library /test/lib28* @build jdk.test.lib.RandomFactory29* @run main/timeout=180 LotsOfEvents30* @key randomness31*/3233import java.io.IOException;34import java.io.OutputStream;35import java.nio.file.*;36import static java.nio.file.StandardWatchEventKinds.*;37import java.util.*;38import java.util.concurrent.TimeUnit;39import jdk.test.lib.RandomFactory;4041public class LotsOfEvents {4243private static final Random RAND = RandomFactory.getRandom();4445public static void main(String[] args) throws Exception {46Path dir = TestUtil.createTemporaryDirectory();47try {48testOverflowEvent(dir);49testModifyEventsQueuing(dir);50} finally {51TestUtil.removeAll(dir);52}53}5455/**56* Tests that OVERFLOW events are not retreived with other events.57*/58static void testOverflowEvent(Path dir)59throws IOException, InterruptedException60{61try (WatchService watcher = dir.getFileSystem().newWatchService()) {62dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE);6364// create a lot of files65int n = 1024;66Path[] files = new Path[n];67for (int i=0; i<n; i++) {68files[i] = Files.createFile(dir.resolve("foo" + i));69}7071// give time for events to accumulate (improve chance of overflow)72Thread.sleep(1000);7374// check that we see the create events (or overflow)75drainAndCheckOverflowEvents(dir, watcher, ENTRY_CREATE, n);7677// delete the files78for (int i=0; i<n; i++) {79Files.delete(files[i]);80}8182// give time for events to accumulate (improve chance of overflow)83Thread.sleep(1000);8485// check that we see the delete events (or overflow)86drainAndCheckOverflowEvents(dir, watcher, ENTRY_DELETE, n);87}88}8990static void drainAndCheckOverflowEvents(Path dir,91WatchService watcher,92WatchEvent.Kind<?> expectedKind,93int count)94throws IOException, InterruptedException95{96// wait for key to be signalled - the timeout is long to allow for97// polling implementations98WatchKey key = watcher.poll(15, TimeUnit.SECONDS);99if (key != null && count == 0)100throw new RuntimeException("Key was signalled (unexpected)");101if (key == null && count > 0)102throw new RuntimeException("Key not signalled (unexpected)");103104int nread = 0;105boolean gotOverflow = false;106while (key != null) {107List<WatchEvent<?>> events = key.pollEvents();108for (WatchEvent<?> event: events) {109WatchEvent.Kind<?> kind = event.kind();110if (kind == expectedKind) {111// expected event kind112if (++nread > count)113throw new RuntimeException("More events than expected!!");114} else if (kind == OVERFLOW) {115// overflow event should not be retrieved with other events116if (events.size() > 1)117throw new RuntimeException("Overflow retrieved with other events");118gotOverflow = true;119} else {120throw new RuntimeException("Unexpected event '" + kind + "'");121}122}123if (!key.reset())124throw new RuntimeException("Key is no longer valid");125key = watcher.poll(2, TimeUnit.SECONDS);126}127128// check that all expected events were received or there was an overflow129if (nread < count && !gotOverflow) {130System.err.printf("Test directory %s contains %d files%n",131dir, Files.list(dir).count());132133long timeBeforePoll = System.nanoTime();134key = watcher.poll(15, TimeUnit.SECONDS);135long timeAfterPoll = System.nanoTime();136if (key == null) {137System.err.println("key still null after extra polling");138} else {139List<WatchEvent<?>> events = key.pollEvents();140System.err.printf("Retrieved key with %d events after %d ns%n",141events.size(), timeAfterPoll - timeBeforePoll);142}143144throw new RuntimeException("Insufficient "145+ expectedKind.name() + " events: expected "146+ count + ", received " + nread);147}148}149150/**151* Tests that check that ENTRY_MODIFY events are queued efficiently152*/153static void testModifyEventsQueuing(Path dir)154throws IOException, InterruptedException155{156// this test uses a random number of files157final int nfiles = 5 + RAND.nextInt(10);158DirectoryEntry[] entries = new DirectoryEntry[nfiles];159for (int i=0; i<nfiles; i++) {160entries[i] = new DirectoryEntry(dir.resolve("foo" + i));161162// "some" of the files exist, some do not.163entries[i].deleteIfExists();164if (RAND.nextBoolean())165entries[i].create();166}167168try (WatchService watcher = dir.getFileSystem().newWatchService()) {169dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);170171// do several rounds of noise and test172for (int round=0; round<10; round++) {173174// make some noise!!!175for (int i=0; i<100; i++) {176DirectoryEntry entry = entries[RAND.nextInt(nfiles)];177int action = RAND.nextInt(10);178switch (action) {179case 0 : entry.create(); break;180case 1 : entry.deleteIfExists(); break;181default: entry.modifyIfExists();182}183}184185// process events and ensure that we don't get repeated modify186// events for the same file.187WatchKey key = watcher.poll(15, TimeUnit.SECONDS);188while (key != null) {189Set<Path> modified = new HashSet<>();190for (WatchEvent<?> event: key.pollEvents()) {191WatchEvent.Kind<?> kind = event.kind();192Path file = (kind == OVERFLOW) ? null : (Path)event.context();193if (kind == ENTRY_MODIFY) {194boolean added = modified.add(file);195if (!added) {196throw new RuntimeException(197"ENTRY_MODIFY events not queued efficiently");198}199} else {200if (file != null) modified.remove(file);201}202}203if (!key.reset())204throw new RuntimeException("Key is no longer valid");205key = watcher.poll(2, TimeUnit.SECONDS);206}207}208}209}210211static class DirectoryEntry {212private final Path file;213DirectoryEntry(Path file) {214this.file = file;215}216void create() throws IOException {217if (Files.notExists(file))218Files.createFile(file);219220}221void deleteIfExists() throws IOException {222Files.deleteIfExists(file);223}224void modifyIfExists() throws IOException {225if (Files.exists(file)) {226try (OutputStream out = Files.newOutputStream(file, StandardOpenOption.APPEND)) {227out.write("message".getBytes());228}229}230}231}232233}234235236