提交 58f86cea 编写于 作者: U uta

8014394: (fs) WatchService failing when watching \\server\$d

Reviewed-by: alanb
上级 b3279192
...@@ -100,6 +100,7 @@ class WindowsConstants { ...@@ -100,6 +100,7 @@ class WindowsConstants {
public static final int ERROR_INVALID_LEVEL = 124; public static final int ERROR_INVALID_LEVEL = 124;
public static final int ERROR_DIR_NOT_EMPTY = 145; public static final int ERROR_DIR_NOT_EMPTY = 145;
public static final int ERROR_ALREADY_EXISTS = 183; public static final int ERROR_ALREADY_EXISTS = 183;
public static final int ERROR_MORE_DATA = 234;
public static final int ERROR_DIRECTORY = 267; public static final int ERROR_DIRECTORY = 267;
public static final int ERROR_NOTIFY_ENUM_DIR = 1022; public static final int ERROR_NOTIFY_ENUM_DIR = 1022;
public static final int ERROR_NONE_MAPPED = 1332; public static final int ERROR_NONE_MAPPED = 1332;
......
...@@ -973,19 +973,19 @@ class WindowsNativeDispatcher { ...@@ -973,19 +973,19 @@ class WindowsNativeDispatcher {
* HANDLE CreateIoCompletionPort ( * HANDLE CreateIoCompletionPort (
* HANDLE FileHandle, * HANDLE FileHandle,
* HANDLE ExistingCompletionPort, * HANDLE ExistingCompletionPort,
* DWORD CompletionKey, * ULONG_PTR CompletionKey,
* DWORD NumberOfConcurrentThreads * DWORD NumberOfConcurrentThreads
* ) * )
*/ */
static native long CreateIoCompletionPort(long fileHandle, long existingPort, static native long CreateIoCompletionPort(long fileHandle, long existingPort,
int completionKey) throws WindowsException; long completionKey) throws WindowsException;
/** /**
* GetQueuedCompletionStatus( * GetQueuedCompletionStatus(
* HANDLE CompletionPort, * HANDLE CompletionPort,
* LPDWORD lpNumberOfBytesTransferred, * LPDWORD lpNumberOfBytesTransferred,
* LPDWORD lpCompletionKey, * PULONG_PTR lpCompletionKey,
* LPOVERLAPPED *lpOverlapped, * LPOVERLAPPED *lpOverlapped,
* DWORD dwMilliseconds * DWORD dwMilliseconds
*/ */
...@@ -999,12 +999,12 @@ class WindowsNativeDispatcher { ...@@ -999,12 +999,12 @@ class WindowsNativeDispatcher {
static class CompletionStatus { static class CompletionStatus {
private int error; private int error;
private int bytesTransferred; private int bytesTransferred;
private int completionKey; private long completionKey;
private CompletionStatus() { } private CompletionStatus() { }
int error() { return error; } int error() { return error; }
int bytesTransferred() { return bytesTransferred; } int bytesTransferred() { return bytesTransferred; }
int completionKey() { return completionKey; } long completionKey() { return completionKey; }
} }
private static native void GetQueuedCompletionStatus0(long completionPort, private static native void GetQueuedCompletionStatus0(long completionPort,
CompletionStatus status) throws WindowsException; CompletionStatus status) throws WindowsException;
...@@ -1013,12 +1013,12 @@ class WindowsNativeDispatcher { ...@@ -1013,12 +1013,12 @@ class WindowsNativeDispatcher {
* PostQueuedCompletionStatus( * PostQueuedCompletionStatus(
* HANDLE CompletionPort, * HANDLE CompletionPort,
* DWORD dwNumberOfBytesTransferred, * DWORD dwNumberOfBytesTransferred,
* DWORD dwCompletionKey, * ULONG_PTR dwCompletionKey,
* LPOVERLAPPED lpOverlapped * LPOVERLAPPED lpOverlapped
* ) * )
*/ */
static native void PostQueuedCompletionStatus(long completionPort, static native void PostQueuedCompletionStatus(long completionPort,
int completionKey) throws WindowsException; long completionKey) throws WindowsException;
/** /**
* ReadDirectoryChangesW( * ReadDirectoryChangesW(
......
...@@ -41,6 +41,7 @@ import static sun.nio.fs.WindowsConstants.*; ...@@ -41,6 +41,7 @@ import static sun.nio.fs.WindowsConstants.*;
class WindowsWatchService class WindowsWatchService
extends AbstractWatchService extends AbstractWatchService
{ {
private final static int WAKEUP_COMPLETION_KEY = 0;
private final Unsafe unsafe = Unsafe.getUnsafe(); private final Unsafe unsafe = Unsafe.getUnsafe();
// background thread to service I/O completion port // background thread to service I/O completion port
...@@ -83,7 +84,7 @@ class WindowsWatchService ...@@ -83,7 +84,7 @@ class WindowsWatchService
*/ */
private class WindowsWatchKey extends AbstractWatchKey { private class WindowsWatchKey extends AbstractWatchKey {
// file key (used to detect existing registrations) // file key (used to detect existing registrations)
private FileKey fileKey; private final FileKey fileKey;
// handle to directory // handle to directory
private volatile long handle = INVALID_HANDLE_VALUE; private volatile long handle = INVALID_HANDLE_VALUE;
...@@ -223,8 +224,7 @@ class WindowsWatchService ...@@ -223,8 +224,7 @@ class WindowsWatchService
FileKey other = (FileKey)obj; FileKey other = (FileKey)obj;
if (this.volSerialNumber != other.volSerialNumber) return false; if (this.volSerialNumber != other.volSerialNumber) return false;
if (this.fileIndexHigh != other.fileIndexHigh) return false; if (this.fileIndexHigh != other.fileIndexHigh) return false;
if (this.fileIndexLow != other.fileIndexLow) return false; return this.fileIndexLow == other.fileIndexLow;
return true;
} }
} }
...@@ -268,6 +268,7 @@ class WindowsWatchService ...@@ -268,6 +268,7 @@ class WindowsWatchService
private static final short OFFSETOF_FILENAME = 12; private static final short OFFSETOF_FILENAME = 12;
// size of per-directory buffer for events (FIXME - make this configurable) // size of per-directory buffer for events (FIXME - make this configurable)
// Need to be less than 4*16384 = 65536. DWORD align.
private static final int CHANGES_BUFFER_SIZE = 16 * 1024; private static final int CHANGES_BUFFER_SIZE = 16 * 1024;
private final WindowsFileSystem fs; private final WindowsFileSystem fs;
...@@ -275,27 +276,28 @@ class WindowsWatchService ...@@ -275,27 +276,28 @@ class WindowsWatchService
private final long port; private final long port;
// maps completion key to WatchKey // maps completion key to WatchKey
private final Map<Integer,WindowsWatchKey> int2key; private final Map<Integer,WindowsWatchKey> ck2key;
// maps file key to WatchKey // maps file key to WatchKey
private final Map<FileKey,WindowsWatchKey> fk2key; private final Map<FileKey,WindowsWatchKey> fk2key;
// unique completion key for each directory // unique completion key for each directory
// native completion key capacity is 64 bits on Win64.
private int lastCompletionKey; private int lastCompletionKey;
Poller(WindowsFileSystem fs, WindowsWatchService watcher, long port) { Poller(WindowsFileSystem fs, WindowsWatchService watcher, long port) {
this.fs = fs; this.fs = fs;
this.watcher = watcher; this.watcher = watcher;
this.port = port; this.port = port;
this.int2key = new HashMap<Integer,WindowsWatchKey>(); this.ck2key = new HashMap<>();
this.fk2key = new HashMap<FileKey,WindowsWatchKey>(); this.fk2key = new HashMap<>();
this.lastCompletionKey = 0; this.lastCompletionKey = 0;
} }
@Override @Override
void wakeup() throws IOException { void wakeup() throws IOException {
try { try {
PostQueuedCompletionStatus(port, 0); PostQueuedCompletionStatus(port, WAKEUP_COMPLETION_KEY);
} catch (WindowsException x) { } catch (WindowsException x) {
throw new IOException(x.getMessage()); throw new IOException(x.getMessage());
} }
...@@ -322,7 +324,6 @@ class WindowsWatchService ...@@ -322,7 +324,6 @@ class WindowsWatchService
for (WatchEvent.Modifier modifier: modifiers) { for (WatchEvent.Modifier modifier: modifiers) {
if (modifier == ExtendedWatchEventModifier.FILE_TREE) { if (modifier == ExtendedWatchEventModifier.FILE_TREE) {
watchSubtree = true; watchSubtree = true;
continue;
} else { } else {
if (modifier == null) if (modifier == null)
return new NullPointerException(); return new NullPointerException();
...@@ -333,7 +334,7 @@ class WindowsWatchService ...@@ -333,7 +334,7 @@ class WindowsWatchService
} }
// open directory // open directory
long handle = -1L; long handle;
try { try {
handle = CreateFile(dir.getPathForWin32Calls(), handle = CreateFile(dir.getPathForWin32Calls(),
FILE_LIST_DIRECTORY, FILE_LIST_DIRECTORY,
...@@ -347,7 +348,7 @@ class WindowsWatchService ...@@ -347,7 +348,7 @@ class WindowsWatchService
boolean registered = false; boolean registered = false;
try { try {
// read attributes and check file is a directory // read attributes and check file is a directory
WindowsFileAttributes attrs = null; WindowsFileAttributes attrs;
try { try {
attrs = WindowsFileAttributes.readAttributes(handle); attrs = WindowsFileAttributes.readAttributes(handle);
} catch (WindowsException x) { } catch (WindowsException x) {
...@@ -370,9 +371,10 @@ class WindowsWatchService ...@@ -370,9 +371,10 @@ class WindowsWatchService
return existing; return existing;
} }
// unique completion key (skip 0) // Can overflow the int type capacity.
// Skip WAKEUP_COMPLETION_KEY value.
int completionKey = ++lastCompletionKey; int completionKey = ++lastCompletionKey;
if (completionKey == 0) if (completionKey == WAKEUP_COMPLETION_KEY)
completionKey = ++lastCompletionKey; completionKey = ++lastCompletionKey;
// associate handle with completion port // associate handle with completion port
...@@ -418,13 +420,13 @@ class WindowsWatchService ...@@ -418,13 +420,13 @@ class WindowsWatchService
// 1. remove mapping from old completion key to existing watch key // 1. remove mapping from old completion key to existing watch key
// 2. release existing key's resources (handle/buffer) // 2. release existing key's resources (handle/buffer)
// 3. re-initialize key with new handle/buffer // 3. re-initialize key with new handle/buffer
int2key.remove(existing.completionKey()); ck2key.remove(existing.completionKey());
existing.releaseResources(); existing.releaseResources();
watchKey = existing.init(handle, events, watchSubtree, buffer, watchKey = existing.init(handle, events, watchSubtree, buffer,
countAddress, overlappedAddress, completionKey); countAddress, overlappedAddress, completionKey);
} }
// map completion map to watch key // map completion map to watch key
int2key.put(completionKey, watchKey); ck2key.put(completionKey, watchKey);
registered = true; registered = true;
return watchKey; return watchKey;
...@@ -440,7 +442,7 @@ class WindowsWatchService ...@@ -440,7 +442,7 @@ class WindowsWatchService
WindowsWatchKey key = (WindowsWatchKey)obj; WindowsWatchKey key = (WindowsWatchKey)obj;
if (key.isValid()) { if (key.isValid()) {
fk2key.remove(key.fileKey()); fk2key.remove(key.fileKey());
int2key.remove(key.completionKey()); ck2key.remove(key.completionKey());
key.invalidate(); key.invalidate();
} }
} }
...@@ -449,11 +451,11 @@ class WindowsWatchService ...@@ -449,11 +451,11 @@ class WindowsWatchService
@Override @Override
void implCloseAll() { void implCloseAll() {
// cancel all keys // cancel all keys
for (Map.Entry<Integer,WindowsWatchKey> entry: int2key.entrySet()) { for (Map.Entry<Integer, WindowsWatchKey> entry: ck2key.entrySet()) {
entry.getValue().invalidate(); entry.getValue().invalidate();
} }
fk2key.clear(); fk2key.clear();
int2key.clear(); ck2key.clear();
// close I/O completion port // close I/O completion port
CloseHandle(port); CloseHandle(port);
...@@ -517,7 +519,7 @@ class WindowsWatchService ...@@ -517,7 +519,7 @@ class WindowsWatchService
@Override @Override
public void run() { public void run() {
for (;;) { for (;;) {
CompletionStatus info = null; CompletionStatus info;
try { try {
info = GetQueuedCompletionStatus(port); info = GetQueuedCompletionStatus(port);
} catch (WindowsException x) { } catch (WindowsException x) {
...@@ -527,7 +529,7 @@ class WindowsWatchService ...@@ -527,7 +529,7 @@ class WindowsWatchService
} }
// wakeup // wakeup
if (info.completionKey() == 0) { if (info.completionKey() == WAKEUP_COMPLETION_KEY) {
boolean shutdown = processRequests(); boolean shutdown = processRequests();
if (shutdown) { if (shutdown) {
return; return;
...@@ -536,7 +538,7 @@ class WindowsWatchService ...@@ -536,7 +538,7 @@ class WindowsWatchService
} }
// map completionKey to get WatchKey // map completionKey to get WatchKey
WindowsWatchKey key = int2key.get(info.completionKey()); WindowsWatchKey key = ck2key.get((int)info.completionKey());
if (key == null) { if (key == null) {
// We get here when a registration is changed. In that case // We get here when a registration is changed. In that case
// the directory is closed which causes an event with the // the directory is closed which causes an event with the
...@@ -544,38 +546,44 @@ class WindowsWatchService ...@@ -544,38 +546,44 @@ class WindowsWatchService
continue; continue;
} }
// ReadDirectoryChangesW failed boolean criticalError = false;
if (info.error() != 0) { int errorCode = info.error();
int messageSize = info.bytesTransferred();
if (errorCode == ERROR_NOTIFY_ENUM_DIR) {
// buffer overflow // buffer overflow
if (info.error() == ERROR_NOTIFY_ENUM_DIR) { key.signalEvent(StandardWatchEventKinds.OVERFLOW, null);
} else if (errorCode != 0 && errorCode != ERROR_MORE_DATA) {
// ReadDirectoryChangesW failed
criticalError = true;
} else {
// ERROR_MORE_DATA is a warning about incomplite
// data transfer over TCP/UDP stack. For the case
// [messageSize] is zero in the most of cases.
if (messageSize > 0) {
// process non-empty events.
processEvents(key, messageSize);
} else if (errorCode == 0) {
// insufficient buffer size
// not described, but can happen.
key.signalEvent(StandardWatchEventKinds.OVERFLOW, null); key.signalEvent(StandardWatchEventKinds.OVERFLOW, null);
} else {
// other error so cancel key
implCancelKey(key);
key.signal();
} }
continue;
}
// process the events // start read for next batch of changes
if (info.bytesTransferred() > 0) { try {
processEvents(key, info.bytesTransferred()); ReadDirectoryChangesW(key.handle(),
} else { key.buffer().address(),
// insufficient buffer size CHANGES_BUFFER_SIZE,
key.signalEvent(StandardWatchEventKinds.OVERFLOW, null); key.watchSubtree(),
ALL_FILE_NOTIFY_EVENTS,
key.countAddress(),
key.overlappedAddress());
} catch (WindowsException x) {
// no choice but to cancel key
criticalError = true;
}
} }
if (criticalError) {
// start read for next batch of changes
try {
ReadDirectoryChangesW(key.handle(),
key.buffer().address(),
CHANGES_BUFFER_SIZE,
key.watchSubtree(),
ALL_FILE_NOTIFY_EVENTS,
key.countAddress(),
key.overlappedAddress());
} catch (WindowsException x) {
// no choice but to cancel key
implCancelKey(key); implCancelKey(key);
key.signal(); key.signal();
} }
......
...@@ -162,7 +162,7 @@ Java_sun_nio_fs_WindowsNativeDispatcher_initIDs(JNIEnv* env, jclass this) ...@@ -162,7 +162,7 @@ Java_sun_nio_fs_WindowsNativeDispatcher_initIDs(JNIEnv* env, jclass this)
} }
completionStatus_error = (*env)->GetFieldID(env, clazz, "error", "I"); completionStatus_error = (*env)->GetFieldID(env, clazz, "error", "I");
completionStatus_bytesTransferred = (*env)->GetFieldID(env, clazz, "bytesTransferred", "I"); completionStatus_bytesTransferred = (*env)->GetFieldID(env, clazz, "bytesTransferred", "I");
completionStatus_completionKey = (*env)->GetFieldID(env, clazz, "completionKey", "I"); completionStatus_completionKey = (*env)->GetFieldID(env, clazz, "completionKey", "J");
clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$BackupResult"); clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$BackupResult");
if (clazz == NULL) { if (clazz == NULL) {
...@@ -1169,12 +1169,11 @@ Java_sun_nio_fs_WindowsNativeDispatcher_GetFinalPathNameByHandle(JNIEnv* env, ...@@ -1169,12 +1169,11 @@ Java_sun_nio_fs_WindowsNativeDispatcher_GetFinalPathNameByHandle(JNIEnv* env,
JNIEXPORT jlong JNICALL JNIEXPORT jlong JNICALL
Java_sun_nio_fs_WindowsNativeDispatcher_CreateIoCompletionPort(JNIEnv* env, jclass this, Java_sun_nio_fs_WindowsNativeDispatcher_CreateIoCompletionPort(JNIEnv* env, jclass this,
jlong fileHandle, jlong existingPort, jint completionKey) jlong fileHandle, jlong existingPort, jlong completionKey)
{ {
ULONG_PTR ck = completionKey;
HANDLE port = CreateIoCompletionPort((HANDLE)jlong_to_ptr(fileHandle), HANDLE port = CreateIoCompletionPort((HANDLE)jlong_to_ptr(fileHandle),
(HANDLE)jlong_to_ptr(existingPort), (HANDLE)jlong_to_ptr(existingPort),
ck, (ULONG_PTR)completionKey,
0); 0);
if (port == NULL) { if (port == NULL) {
throwWindowsException(env, GetLastError()); throwWindowsException(env, GetLastError());
...@@ -1203,21 +1202,20 @@ Java_sun_nio_fs_WindowsNativeDispatcher_GetQueuedCompletionStatus0(JNIEnv* env, ...@@ -1203,21 +1202,20 @@ Java_sun_nio_fs_WindowsNativeDispatcher_GetQueuedCompletionStatus0(JNIEnv* env,
(*env)->SetIntField(env, obj, completionStatus_error, ioResult); (*env)->SetIntField(env, obj, completionStatus_error, ioResult);
(*env)->SetIntField(env, obj, completionStatus_bytesTransferred, (*env)->SetIntField(env, obj, completionStatus_bytesTransferred,
(jint)bytesTransferred); (jint)bytesTransferred);
(*env)->SetIntField(env, obj, completionStatus_completionKey, (*env)->SetLongField(env, obj, completionStatus_completionKey,
(jint)completionKey); (jlong)completionKey);
} }
} }
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_sun_nio_fs_WindowsNativeDispatcher_PostQueuedCompletionStatus(JNIEnv* env, jclass this, Java_sun_nio_fs_WindowsNativeDispatcher_PostQueuedCompletionStatus(JNIEnv* env, jclass this,
jlong completionPort, jint completionKey) jlong completionPort, jlong completionKey)
{ {
BOOL res; BOOL res;
res = PostQueuedCompletionStatus((HANDLE)jlong_to_ptr(completionPort), res = PostQueuedCompletionStatus((HANDLE)jlong_to_ptr(completionPort),
(DWORD)0, /* dwNumberOfBytesTransferred */ (DWORD)0, /* dwNumberOfBytesTransferred */
(DWORD)completionKey, (ULONG_PTR)completionKey,
NULL); /* lpOverlapped */ NULL); /* lpOverlapped */
if (res == 0) { if (res == 0) {
throwWindowsException(env, GetLastError()); throwWindowsException(env, GetLastError());
...@@ -1232,7 +1230,17 @@ Java_sun_nio_fs_WindowsNativeDispatcher_ReadDirectoryChangesW(JNIEnv* env, jclas ...@@ -1232,7 +1230,17 @@ Java_sun_nio_fs_WindowsNativeDispatcher_ReadDirectoryChangesW(JNIEnv* env, jclas
BOOL res; BOOL res;
BOOL subtree = (watchSubTree == JNI_TRUE) ? TRUE : FALSE; BOOL subtree = (watchSubTree == JNI_TRUE) ? TRUE : FALSE;
((LPOVERLAPPED)jlong_to_ptr(pOverlapped))->hEvent = NULL; /* Any unused members of [OVERLAPPED] structure should always be initialized to zero
before the structure is used in a function call.
Otherwise, the function may fail and return ERROR_INVALID_PARAMETER.
http://msdn.microsoft.com/en-us/library/windows/desktop/ms684342%28v=vs.85%29.aspx
The [Offset] and [OffsetHigh] members of this structure are not used.
http://msdn.microsoft.com/en-us/library/windows/desktop/aa365465%28v=vs.85%29.aspx
[hEvent] should be zero, other fields are the return values. */
ZeroMemory((LPOVERLAPPED)jlong_to_ptr(pOverlapped), sizeof(OVERLAPPED));
res = ReadDirectoryChangesW((HANDLE)jlong_to_ptr(hDirectory), res = ReadDirectoryChangesW((HANDLE)jlong_to_ptr(hDirectory),
(LPVOID)jlong_to_ptr(bufferAddress), (LPVOID)jlong_to_ptr(bufferAddress),
(DWORD)bufferLength, (DWORD)bufferLength,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册