Index: lucene/src/test/org/apache/lucene/search/TestSearchWithThreads.java =================================================================== --- lucene/src/test/org/apache/lucene/search/TestSearchWithThreads.java (revision 0) +++ lucene/src/test/org/apache/lucene/search/TestSearchWithThreads.java (revision 0) @@ -0,0 +1,109 @@ +package org.apache.lucene.search; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; + +import org.apache.lucene.document.Document; +import org.apache.lucene.document.Field; +import org.apache.lucene.index.IndexReader; +import org.apache.lucene.index.RandomIndexWriter; +import org.apache.lucene.index.Term; +import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.store.Directory; +import org.apache.lucene.util.LuceneTestCase; + +public class TestSearchWithThreads extends LuceneTestCase { + + final int NUM_DOCS = 10000; + final int NUM_SEARCH_THREADS = 5; + final int RUN_TIME_MSEC = 1000 * RANDOM_MULTIPLIER; + + public void test() throws Exception { + final Directory dir = newDirectory(); + final RandomIndexWriter w = new RandomIndexWriter(random, dir); + + final long startTime = System.currentTimeMillis(); + + // TODO: replace w/ the @nightly test data; make this + // into an optional @nightly stress test + final Document doc = new Document(); + final Field body = newField("body", "", Field.Index.ANALYZED); + doc.add(body); + final StringBuilder sb = new StringBuilder(); + for(int docCount=0;docCount 0); + netSearch.addAndGet(totSearch); + } catch (Exception exc) { + failed.set(true); + throw new RuntimeException(exc); + } + } + }; + threads[threadID].setDaemon(true); + threads[threadID].start(); + } + + for(int threadID=0;threadID + * Steps: + *
    + *
  1. Compile the source code to create WindowsDirectory.dll: + *
    + * c:\mingw\bin\g++ -Wall -D_JNI_IMPLEMENTATION_ -Wl,--kill-at + * -I"%JAVA_HOME%\include" -I"%JAVA_HOME%\include\win32" -static-libgcc + * -static-libstdc++ -shared WindowsDirectory.cpp -o WindowsDirectory.dll + *
    + * For 64-bit JREs, use mingw64, with the -m64 option. + *
  2. Put WindowsDirectory.dll into some directory in your windows PATH + *
  3. Open indexes with WindowsDirectory and use it. + *

    + * @lucene.experimental + */ +public class WindowsDirectory extends FSDirectory { + + static { + System.loadLibrary("WindowsDirectory"); + } + + /** Create a new WindowsDirectory for the named location. + * + * @param path the path of the directory + * @param lockFactory the lock factory to use, or null for the default + * ({@link NativeFSLockFactory}); + * @throws IOException + */ + public WindowsDirectory(File path, LockFactory lockFactory) throws IOException { + super(path, lockFactory); + } + + /** Create a new WindowsDirectory for the named location and {@link NativeFSLockFactory}. + * + * @param path the path of the directory + * @throws IOException + */ + public WindowsDirectory(File path) throws IOException { + super(path, null); + } + + public IndexInput openInput(String name, int bufferSize) throws IOException { + ensureOpen(); + return new WindowsIndexInput(new File(getDirectory(), name), bufferSize); + } + + protected static class WindowsIndexInput extends BufferedIndexInput { + private final long fd; + private final long length; + boolean isClone; + boolean isOpen; + + public WindowsIndexInput(File file, int bufferSize) throws IOException { + super(bufferSize); + fd = WindowsDirectory.open(file.getPath()); + length = WindowsDirectory.length(fd); + isOpen = true; + } + + protected void readInternal(byte[] b, int offset, int length) throws IOException { + if (WindowsDirectory.read(fd, b, offset, length, getFilePointer()) != length) + throw new IOException("Read past EOF"); + } + + protected void seekInternal(long pos) throws IOException { + } + + public synchronized void close() throws IOException { + // NOTE: we synchronize and track "isOpen" because Lucene sometimes closes IIs twice! + if (!isClone && isOpen) { + WindowsDirectory.close(fd); + isOpen = false; + } + } + + public long length() { + return length; + } + + @Override + public Object clone() { + WindowsIndexInput clone = (WindowsIndexInput)super.clone(); + clone.isClone = true; + return clone; + } + } + + /** Opens a handle to a file. */ + private static native long open(String filename) throws IOException; + + /** Reads data from a file at pos into bytes */ + private static native int read(long fd, byte bytes[], int offset, int length, long pos) throws IOException; + + /** Closes a handle to a file */ + private static native void close(long fd) throws IOException; + + /** Returns the length of a file */ + private static native long length(long fd) throws IOException; +} Property changes on: lucene\contrib\misc\src\java\org\apache\lucene\store\WindowsDirectory.java ___________________________________________________________________ Added: svn:eol-style + native Index: lucene/contrib/misc/src/java/org/apache/lucene/store/WindowsDirectory.cpp =================================================================== --- lucene/contrib/misc/src/java/org/apache/lucene/store/WindowsDirectory.cpp (revision 0) +++ lucene/contrib/misc/src/java/org/apache/lucene/store/WindowsDirectory.cpp (revision 0) @@ -0,0 +1,181 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +#include +#include "windows.h" + +/** + * Windows Native IO methods. + */ +extern "C" { + +/** + * Utility to format a Windows system error code into an exception. + */ +void throwIOException(JNIEnv *env, DWORD error) +{ + jclass ioex; + char *msg; + + ioex = env->FindClass("java/io/IOException"); + + if (ioex != NULL) { + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &msg, 0, NULL ); + env->ThrowNew(ioex, msg); + LocalFree(msg); + } +} + +/** + * Utility to throw Exceptions on bad input + */ +void throwException(JNIEnv *env, const char *clazz, const char *msg) +{ + jclass exc = env->FindClass(clazz); + + if (exc != NULL) { + env->ThrowNew(exc, msg); + } +} + +/** + * Opens a handle to a file. + * + * Class: org_apache_lucene_store_WindowsDirectory + * Method: open + * Signature: (Ljava/lang/String;)J + */ +JNIEXPORT jlong JNICALL Java_org_apache_lucene_store_WindowsDirectory_open + (JNIEnv *env, jclass ignored, jstring filename) +{ + char *fname; + HANDLE handle; + jboolean isCopy; + + if (filename == NULL) { + throwException(env, "java/lang/NullPointerException", "filename cannot be null"); + return -1; + } + + fname = (char *) env->GetStringUTFChars(filename, &isCopy); + + if (fname == NULL) { + throwException(env, "java/lang/IllegalArgumentException", "invalid filename"); + return -1; + } + + handle = CreateFile(fname, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, NULL); + + if (isCopy) { + env->ReleaseStringUTFChars(filename, fname); + } + + if (handle == INVALID_HANDLE_VALUE) { + throwIOException(env, GetLastError()); + return -1; + } + + return (jlong) handle; +} + +/** + * Reads data into the byte array, starting at offset, for length characters. + * The read is positioned at pos. + * + * Class: org_apache_lucene_store_WindowsDirectory + * Method: read + * Signature: (J[BIIJ)I + */ +JNIEXPORT jint JNICALL Java_org_apache_lucene_store_WindowsDirectory_read + (JNIEnv *env, jclass ignored, jlong fd, jbyteArray bytes, jint offset, jint length, jlong pos) +{ + OVERLAPPED io = { 0 }; + DWORD numRead = -1; + + io.Offset = (DWORD) (pos & 0xFFFFFFFF); + io.OffsetHigh = (DWORD) ((pos >> 0x20) & 0x7FFFFFFF); + + if (bytes == NULL) { + throwException(env, "java/lang/NullPointerException", "bytes cannot be null"); + return -1; + } + + if (length <= 2048) { /* For small buffers, avoid GetByteArrayElements' copy */ + char buffer[length]; + + if (ReadFile((HANDLE) fd, &buffer, length, &numRead, &io)) { + env->SetByteArrayRegion(bytes, offset, numRead, (const jbyte *) buffer); + } else { + throwIOException(env, GetLastError()); + numRead = -1; + } + + } else { + jboolean isCopy; + jbyte *buffer = env->GetByteArrayElements (bytes, &isCopy); + + if (!ReadFile((HANDLE) fd, (void *)(buffer+offset), length, &numRead, &io)) { + throwIOException(env, GetLastError()); + numRead = -1; + } + + if (isCopy == JNI_TRUE) { + env->ReleaseByteArrayElements(bytes, buffer, numRead == 0 || numRead == -1 ? JNI_ABORT : 0); + } + } + + return numRead; +} + +/** + * Closes a handle to a file + * + * Class: org_apache_lucene_store_WindowsDirectory + * Method: close + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_org_apache_lucene_store_WindowsDirectory_close + (JNIEnv *env, jclass ignored, jlong fd) +{ + if (!CloseHandle((HANDLE) fd)) { + throwIOException(env, GetLastError()); + } +} + +/** + * Returns the length in bytes of a file. + * + * Class: org_apache_lucene_store_WindowsDirectory + * Method: length + * Signature: (J)J + */ +JNIEXPORT jlong JNICALL Java_org_apache_lucene_store_WindowsDirectory_length + (JNIEnv *env, jclass ignored, jlong fd) +{ + BY_HANDLE_FILE_INFORMATION info; + + if (GetFileInformationByHandle((HANDLE) fd, (LPBY_HANDLE_FILE_INFORMATION) &info)) { + return (jlong) (((DWORDLONG) info.nFileSizeHigh << 0x20) + info.nFileSizeLow); + } else { + throwIOException(env, GetLastError()); + return -1; + } +} + +} /* extern "C" */ Property changes on: lucene\contrib\misc\src\java\org\apache\lucene\store\WindowsDirectory.cpp ___________________________________________________________________ Added: svn:eol-style + native