Created
March 28, 2012 04:10
-
-
Save slingamn/2223536 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/.gitignore b/.gitignore | |
new file mode 100644 | |
index 0000000..cbb1d4b | |
--- /dev/null | |
+++ b/.gitignore | |
@@ -0,0 +1,3 @@ | |
+build | |
+*.class | |
+*.swp | |
diff --git a/clean b/clean | |
new file mode 100755 | |
index 0000000..8b346ec | |
--- /dev/null | |
+++ b/clean | |
@@ -0,0 +1,3 @@ | |
+#!/bin/sh -e | |
+ | |
+rm *.h *.class *.o *.so | |
diff --git a/common-build.xml b/common-build.xml | |
index e202576..dcd2ff7 100644 | |
--- a/common-build.xml | |
+++ b/common-build.xml | |
@@ -58,10 +58,10 @@ | |
<property name="javac.deprecation" value="off"/> | |
<property name="javac.debug" value="on"/> | |
- <property name="javac.source" value="1.4"/> | |
- <property name="javac.target" value="1.4"/> | |
+ <property name="javac.source" value="1.6"/> | |
+ <property name="javac.target" value="1.6"/> | |
- <property name="javadoc.link" value="http://java.sun.com/j2se/1.4/docs/api/"/> | |
+ <property name="javadoc.link" value="http://java.sun.com/j2se/1.6/docs/api/"/> | |
<property name="javadoc.access" value="protected"/> | |
<property name="javadoc.charset" value="utf-8"/> | |
<property name="javadoc.dir" value="${common.dir}/build/docs/api"/> | |
diff --git a/shortbuild b/shortbuild | |
new file mode 100755 | |
index 0000000..7c7968f | |
--- /dev/null | |
+++ b/shortbuild | |
@@ -0,0 +1,10 @@ | |
+#!/bin/sh -e | |
+ | |
+#javac SystemCallException.java | |
+DIR="src/java/org/apache/lucene/store" | |
+ | |
+ant | |
+ | |
+CLASSPATH=build/lucene-core-2.9.4-dev.jar javah org.apache.lucene.store.JNIMman | |
+gcc -fPIC -g -c -Wall -I/usr/lib/jvm/java/include -I/usr/lib/jvm/java/include/linux ${DIR}/JNIMman.c | |
+gcc -shared -W1,-soname,jnimman.so.1 -o libjnimman.so JNIMman.o -lc | |
diff --git a/src/java/org/apache/lucene/store/JNILinuxConstants.java b/src/java/org/apache/lucene/store/JNILinuxConstants.java | |
new file mode 100644 | |
index 0000000..16d9096 | |
--- /dev/null | |
+++ b/src/java/org/apache/lucene/store/JNILinuxConstants.java | |
@@ -0,0 +1,27 @@ | |
+package org.apache.lucene.store; | |
+ | |
+class JNILinuxConstants { | |
+ | |
+ /* TODO replace this, obviously */ | |
+ | |
+ public static final int O_RDONLY = 0; | |
+ public static final int O_WRONLY = 1; | |
+ public static final int O_RDWR = 2; | |
+ | |
+ // protection settings for mmap | |
+ public static final int PROT_NONE = 0; | |
+ public static final int PROT_READ = 1; | |
+ public static final int PROT_WRITE = 2; | |
+ public static final int PROT_EXEC = 4; | |
+ | |
+ // map modes | |
+ public static final int MAP_SHARED = 1; | |
+ public static final int MAP_PRIVATE = 2; | |
+ | |
+ // mlock and mlockall | |
+ public static final int MCL_CURRENT = 1; | |
+ public static final int MCL_FUTURE = 2; | |
+ | |
+ // sysconf values | |
+ public static final int _SC_PAGESIZE = 30; | |
+} | |
diff --git a/src/java/org/apache/lucene/store/JNIMman.c b/src/java/org/apache/lucene/store/JNIMman.c | |
new file mode 100644 | |
index 0000000..5087755 | |
--- /dev/null | |
+++ b/src/java/org/apache/lucene/store/JNIMman.c | |
@@ -0,0 +1,144 @@ | |
+#include <jni.h> | |
+ | |
+#include <inttypes.h> | |
+#include <errno.h> | |
+#include <fcntl.h> | |
+#include <unistd.h> | |
+#include <sys/mman.h> | |
+#include <sys/stat.h> | |
+ | |
+void Java_org_apache_lucene_store_JNIMman_throw_exception(JNIEnv *env, int saved_errno) { | |
+ jclass new_exc_cls; | |
+ jmethodID cid; | |
+ /* TODO proper packaging */ | |
+ new_exc_cls = (*env)->FindClass(env, "SystemCallException"); | |
+ // printf("found cls %p\n", new_exc_cls); | |
+ cid = (*env)->GetMethodID(env, new_exc_cls, "<init>", "(I)V"); | |
+ //printf("found cons %p\n", cid); | |
+ jobject exc = (*env)->NewObject(env, new_exc_cls, cid, (jint) saved_errno); | |
+ (*env)->Throw(env, exc); | |
+} | |
+ | |
+JNIEXPORT jint JNICALL Java_org_apache_lucene_store_JNIMman_mlock | |
+ (JNIEnv *env, jclass cls, jlong addr, jlong len) { | |
+ /* len is an actual signed Java long */ | |
+ size_t native_len = (size_t) ((long) len); | |
+ int result = mlock((void *) addr, native_len); | |
+ if (result == -1) { | |
+ Java_org_apache_lucene_store_JNIMman_throw_exception(env, errno); | |
+ } | |
+ return (jint) result; | |
+ } | |
+ | |
+/* | |
+ * Class: JNIMman | |
+ * Method: munlock | |
+ * Signature: (JJ)I | |
+ */ | |
+JNIEXPORT jint JNICALL Java_org_apache_lucene_store_JNIMman_munlock | |
+ (JNIEnv *env, jclass cls, jlong addr, jlong len) { | |
+ /* len is an actual signed Java long */ | |
+ size_t native_len = (size_t) ((long) len); | |
+ int result = munlock((void *) addr, native_len); | |
+ if (result == -1) { | |
+ Java_org_apache_lucene_store_JNIMman_throw_exception(env, errno); | |
+ } | |
+ return (jint) result; | |
+ } | |
+ | |
+/* | |
+ * Class: JNIMman | |
+ * Method: mlockall | |
+ * Signature: (I)I | |
+ */ | |
+JNIEXPORT jint JNICALL Java_org_apache_lucene_store_JNIMman_mlockall | |
+ (JNIEnv *env, jclass cls, jint flags) { | |
+ int result = mlockall((int) flags); | |
+ if (result == -1) { | |
+ Java_org_apache_lucene_store_JNIMman_throw_exception(env, errno); | |
+ } | |
+ return (jint) result; | |
+ } | |
+ | |
+/* | |
+ * Class: JNIMman | |
+ * Method: munlockall | |
+ * Signature: ()I | |
+ */ | |
+JNIEXPORT jint JNICALL Java_org_apache_lucene_store_JNIMman_munlockall | |
+ (JNIEnv *env, jclass cls) { | |
+ int result = munlockall(); | |
+ if (result == -1) { | |
+ Java_org_apache_lucene_store_JNIMman_throw_exception(env, errno); | |
+ } | |
+ return (jint) result; | |
+ } | |
+ | |
+JNIEXPORT jlong JNICALL Java_org_apache_lucene_store_JNIMman_mmap | |
+ (JNIEnv *env, jclass cls, jlong addr, jlong length, jint prot, jint flags, | |
+ jint fd, jlong offset) { | |
+ void *result = mmap((void *) addr, (size_t) length, (int) prot, | |
+ (int) flags, (int) fd, (off_t) offset); | |
+ if (result == MAP_FAILED) { | |
+ Java_org_apache_lucene_store_JNIMman_throw_exception(env, errno); | |
+ } | |
+ /* TODO is conversion right here? i just want to stuff the eight bytes */ | |
+ return (jlong) result; | |
+ } | |
+ | |
+JNIEXPORT jint JNICALL Java_org_apache_lucene_store_JNIMman_munmap | |
+ (JNIEnv * env, jclass cls, jlong addr, jlong length) { | |
+ int result = munmap((void *) addr, (size_t) length); | |
+ if (result == -1) Java_org_apache_lucene_store_JNIMman_throw_exception(env, errno); | |
+ return (jint) result; | |
+ } | |
+ | |
+JNIEXPORT jint JNICALL Java_org_apache_lucene_store_JNIMman_open__Ljava_lang_String_2II | |
+ (JNIEnv * env, jclass cls, jstring path, jint flags, jint mode) { | |
+ jboolean iscopy; | |
+ int fd; | |
+ | |
+ const char *mfile = (*env)->GetStringUTFChars(env, path, &iscopy); | |
+ fd = open(mfile, (int) flags, (int) mode); | |
+ if (fd == -1) Java_org_apache_lucene_store_JNIMman_throw_exception(env, errno); | |
+ (*env)->ReleaseStringUTFChars(env, path, mfile); | |
+ return (jint) fd; | |
+ } | |
+ | |
+JNIEXPORT jint JNICALL Java_org_apache_lucene_store_JNIMman_open__Ljava_lang_String_2I | |
+ (JNIEnv * env, jclass cls, jstring path, jint flags) { | |
+ /* TODO is this actually a "default" mode argument :-| */ | |
+ return Java_org_apache_lucene_store_JNIMman_open__Ljava_lang_String_2II(env, cls, path, flags, 0777); | |
+ } | |
+ | |
+JNIEXPORT jint JNICALL Java_org_apache_lucene_store_JNIMman_close | |
+ (JNIEnv * env, jclass cls, jint fd) { | |
+ int result = close((int) fd); | |
+ if (result == -1) Java_org_apache_lucene_store_JNIMman_throw_exception(env, errno); | |
+ return (jint) result; | |
+ } | |
+ | |
+JNIEXPORT jlong JNICALL Java_org_apache_lucene_store_JNIMman_sysconf | |
+ (JNIEnv *env, jclass cls, jint name) { | |
+ long result = sysconf((int) name); | |
+ if (result == -1) Java_org_apache_lucene_store_JNIMman_throw_exception(env, errno); | |
+ return result; | |
+ } | |
+ | |
+JNIEXPORT jbyte JNICALL Java_org_apache_lucene_store_JNIMman_getByte | |
+ (JNIEnv *env, jclass cls, jlong addr, jlong offset) { | |
+ /* don't perform pointer arithmetic in Javaspace; | |
+ wraparound overflow would be correct but the Java | |
+ behavior is to truncate. */ | |
+ jbyte *byte_addr = (jbyte *) addr + offset; | |
+ return *byte_addr; | |
+ } | |
+ | |
+JNIEXPORT void JNICALL Java_org_apache_lucene_store_JNIMman_getBytes | |
+ (JNIEnv *env, jclass cls, jbyteArray buf, jint offset, jint len, | |
+ jlong addr, jlong addr_offset) { | |
+ /* see above caution about pointer arithmetic in Javaspace */ | |
+ jbyte *byte_addr = (jbyte *) addr + addr_offset; | |
+ /* may set an ArrayIndexOutOfBoundsException */ | |
+ (*env)->SetByteArrayRegion(env, buf, offset, len, byte_addr); | |
+ } | |
diff --git a/src/java/org/apache/lucene/store/JNIMman.java b/src/java/org/apache/lucene/store/JNIMman.java | |
new file mode 100644 | |
index 0000000..0094cd0 | |
--- /dev/null | |
+++ b/src/java/org/apache/lucene/store/JNIMman.java | |
@@ -0,0 +1,57 @@ | |
+package org.apache.lucene.store; | |
+ | |
+/** | |
+ * JNI interface to Linux's sys/mman.h. | |
+ * | |
+ * All of this stuff is POSIX but no promises re. portability. | |
+ * | |
+ * @author [email protected] | |
+ * | |
+ */ | |
+ | |
+class JNIMman { | |
+ | |
+ public static final long NULL = 0; | |
+ | |
+ static { | |
+ System.loadLibrary("jnimman"); | |
+ } | |
+ | |
+ // int mlock(const void *addr, size_t len); | |
+ public native static int mlock(long addr, long len); | |
+ | |
+ // int munlock(const void *addr, size_t len); | |
+ public native static int munlock(long addr, long len); | |
+ | |
+ // int mlockall(int flags); | |
+ public native static int mlockall(int flags); | |
+ | |
+ // int munlockall(void); | |
+ public native static int munlockall(); | |
+ | |
+ // void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); | |
+ public native static long mmap(long addr, long length, int prot, int flags, int fd, long offset); | |
+ | |
+ // int munmap(void *addr, size_t length); | |
+ public native static int munmap(long addr, long length); | |
+ | |
+ // int open(const char *path, int flags); | |
+ public native static int open(String path, int flags); | |
+ // int open(const char *path, int flags, mode_t mode); | |
+ public native static int open(String path, int flags, int mode); | |
+ // int close(int fd); | |
+ public native static int close(int fd); | |
+ | |
+ // long sysconf(int name); | |
+ public native static long sysconf(int name); | |
+ | |
+ // direct access to the address space | |
+ public static native byte getByte(long addr, long offset); | |
+ public static native void getBytes(byte[] buffer, int offset, int len, long addr, long addrOffset); | |
+ | |
+ public static void main(String args[]) { | |
+ System.out.println("Hello world"); | |
+ int result = JNIMman.mlockall(3); | |
+ System.out.println("mlockall returned: " + result); | |
+ } | |
+} | |
diff --git a/src/java/org/apache/lucene/store/MLockDirectory.java b/src/java/org/apache/lucene/store/MLockDirectory.java | |
new file mode 100644 | |
index 0000000..ca0cd86 | |
--- /dev/null | |
+++ b/src/java/org/apache/lucene/store/MLockDirectory.java | |
@@ -0,0 +1,99 @@ | |
+package org.apache.lucene.store; | |
+ | |
+import java.io.File; | |
+import java.io.IOException; | |
+import java.util.HashMap; | |
+ | |
+public class MLockDirectory extends FSDirectory { | |
+ | |
+ private HashMap<String, MMapPlaceholder> fileMap = new HashMap<String, MMapPlaceholder>(); | |
+ private long timeCreated; | |
+ | |
+ private boolean mlock; | |
+ | |
+ File path; | |
+ | |
+ public MLockDirectory(File path, boolean vmtouchFiles, boolean mlock) throws IOException { | |
+ super(path, new NativeFSLockFactory()); | |
+ this.path = path; | |
+ this.mlock = mlock; | |
+ this.timeCreated = System.currentTimeMillis(); | |
+ | |
+ for (String filename : this.listAll()) { | |
+ MMapPlaceholder placeholder = new MMapPlaceholder(filename); | |
+ if (vmtouchFiles) { | |
+ placeholder.vmtouchFile(); | |
+ } | |
+ fileMap.put(filename, placeholder); | |
+ } | |
+ | |
+ if (mlock) { | |
+ JNIMman.mlockall(JNILinuxConstants.MCL_CURRENT); | |
+ } | |
+ } | |
+ | |
+ public void close() { | |
+ if (mlock) { | |
+ JNIMman.munlockall(); | |
+ } | |
+ | |
+ // just close all the underlying mmaps | |
+ for (MMapPlaceholder p : fileMap.values()) { | |
+ p.close(); | |
+ } | |
+ } | |
+ | |
+ // TODO consider a BufferedIndexInput? | |
+ // depends on the cost of the JNI call boundary | |
+ static class MLockIndexInput extends IndexInput { | |
+ MMapPlaceholder placeholder; | |
+ long filePointer = 0; | |
+ | |
+ protected MLockIndexInput(MMapPlaceholder placeholder) { | |
+ super(); | |
+ this.placeholder = placeholder; | |
+ } | |
+ | |
+ public void close() { | |
+ // no-op | |
+ } | |
+ | |
+ public long getFilePointer() { | |
+ return this.filePointer; | |
+ } | |
+ | |
+ public void seek(long pos) { | |
+ this.filePointer = pos; | |
+ } | |
+ | |
+ public long length() { | |
+ return this.placeholder.getLength(); | |
+ } | |
+ | |
+ public byte readByte() { | |
+ return this.placeholder.readByte(this.filePointer); | |
+ } | |
+ | |
+ public void readBytes(byte[] b, int offset, int len) { | |
+ this.placeholder.readBytes(b, offset, len, this.filePointer); | |
+ } | |
+ | |
+ } | |
+ | |
+ public IndexInput openInput(String name) throws IOException { | |
+ MMapPlaceholder placeholder = this.fileMap.get(name); | |
+ if (placeholder == null) { | |
+ throw new IOException("No file named " + name); | |
+ } | |
+ return new MLockIndexInput(placeholder); | |
+ } | |
+ | |
+ public IndexOutput createOutput(String name) { | |
+ return null; | |
+ } | |
+ | |
+ public final long fileLength(String name) { | |
+ return this.fileMap.get(name).getLength(); | |
+ } | |
+ | |
+} | |
diff --git a/src/java/org/apache/lucene/store/MMapPlaceholder.java b/src/java/org/apache/lucene/store/MMapPlaceholder.java | |
new file mode 100644 | |
index 0000000..ec1c20f | |
--- /dev/null | |
+++ b/src/java/org/apache/lucene/store/MMapPlaceholder.java | |
@@ -0,0 +1,84 @@ | |
+package org.apache.lucene.store; | |
+ | |
+import java.io.File; | |
+import java.io.IOException; | |
+ | |
+class MMapPlaceholder { | |
+ | |
+ File file; | |
+ String fileName; | |
+ | |
+ int fd; | |
+ long addr; | |
+ long length; | |
+ | |
+ boolean writeable = false; | |
+ | |
+ public static final long pagesize = JNIMman.sysconf(JNILinuxConstants._SC_PAGESIZE); | |
+ | |
+ public MMapPlaceholder(String name) { | |
+ this(name, false, false); | |
+ } | |
+ | |
+ public MMapPlaceholder(File file) { | |
+ this(file.getName(), false, false); | |
+ } | |
+ | |
+ public MMapPlaceholder(String name, boolean private_map, boolean writeable_map) { | |
+ /* stat the file; don't bother going through the actual stat(2) */ | |
+ this.fileName = name; | |
+ this.file = new File(name); | |
+ this.length = file.length(); | |
+ | |
+ int mode = JNILinuxConstants.MAP_SHARED; | |
+ if (private_map) { | |
+ mode = JNILinuxConstants.MAP_PRIVATE; | |
+ } | |
+ | |
+ int prot = JNILinuxConstants.PROT_READ; | |
+ if (writeable_map) { | |
+ this.writeable = writeable; | |
+ prot |= JNILinuxConstants.PROT_WRITE; | |
+ } | |
+ | |
+ this.fd = JNIMman.open(name, JNILinuxConstants.O_RDONLY, 0); | |
+ this.addr = JNIMman.mmap(0, this.length, prot, mode, this.fd, 0); | |
+ } | |
+ | |
+ public void close() { | |
+ JNIMman.munmap(this.addr, this.fd); | |
+ JNIMman.close(this.fd); | |
+ } | |
+ | |
+ public long getLength() { | |
+ return this.length; | |
+ } | |
+ | |
+ public byte readByte(long offset) { | |
+ return JNIMman.getByte(this.addr, offset); | |
+ } | |
+ | |
+ public void readBytes(byte[] b, int bufferOffset, int length, long fileOffset) { | |
+ JNIMman.getBytes(b, bufferOffset, length, this.addr, fileOffset); | |
+ } | |
+ | |
+ public void vmtouchFile() { | |
+ // read a byte from every page, as per hoyte's vmtouch | |
+ long pages_in_file = (length + pagesize - 1) / pagesize; | |
+ for (long pos = 0; pos < this.length; pos += this.pagesize) { | |
+ readByte(pos); | |
+ } | |
+ } | |
+ | |
+ public static void main(String args[]) { | |
+ MMapPlaceholder p = new MMapPlaceholder("/etc/passwd"); | |
+ byte[] b = new byte[128]; | |
+ char c = (char) p.readByte(0); | |
+ System.out.println("Read the 0th byte: " + c); | |
+ p.readBytes(b, 0, 27, 21); | |
+ System.out.println("Read bytes 21-40: " + new String(b)); | |
+ p.vmtouchFile(); | |
+ System.out.println("vmtouch OK."); | |
+ } | |
+ | |
+} | |
diff --git a/src/java/org/apache/lucene/store/SystemCallException.java b/src/java/org/apache/lucene/store/SystemCallException.java | |
new file mode 100644 | |
index 0000000..9427142 | |
--- /dev/null | |
+++ b/src/java/org/apache/lucene/store/SystemCallException.java | |
@@ -0,0 +1,18 @@ | |
+import java.lang.Exception; | |
+ | |
+class SystemCallException extends Exception { | |
+ | |
+ int errno = -1; | |
+ | |
+ public SystemCallException() { | |
+ super("SystemCallException: errno=?"); | |
+ } | |
+ | |
+ public SystemCallException(int errno) { | |
+ super("SystemCallException: errno=" + errno); | |
+ } | |
+ | |
+ public int getErrno() { | |
+ return this.errno; | |
+ } | |
+} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment