You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by th...@apache.org on 2012/01/25 09:24:05 UTC

svn commit: r1235674 - in /jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/fs: FileCache.java FilePathCache.java FileUtils.java

Author: thomasm
Date: Wed Jan 25 08:24:04 2012
New Revision: 1235674

URL: http://svn.apache.org/viewvc?rev=1235674&view=rev
Log:
Write-behind cache

Modified:
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/fs/FileCache.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/fs/FilePathCache.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/fs/FileUtils.java

Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/fs/FileCache.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/fs/FileCache.java?rev=1235674&r1=1235673&r2=1235674&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/fs/FileCache.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/fs/FileCache.java Wed Jan 25 08:24:04 2012
@@ -16,11 +16,13 @@
  */
 package org.apache.jackrabbit.mk.fs;
 
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.nio.channels.FileChannel;
 import java.nio.channels.FileLock;
 import java.util.Map;
+import java.util.concurrent.atomic.AtomicReference;
 import org.apache.jackrabbit.mk.util.SimpleLRUCache;
 
 /**
@@ -28,12 +30,22 @@ import org.apache.jackrabbit.mk.util.Sim
  */
 public class FileCache extends FileBase {
 
+    private static final boolean APPEND_BUFFER = !Boolean.getBoolean("mk.disableAppendBuffer");
+    private static final int APPEND_BUFFER_SIZE_INIT = 8 * 1024;
+    private static final int APPEND_BUFFER_SIZE = 8 * 1024;
+
     private static final int BLOCK_SIZE = 4 * 1024;
+    private final String name;
     private final Map<Long, ByteBuffer> readCache = SimpleLRUCache.newInstance(16);
     private final FileChannel base;
     private long pos, size;
 
-    FileCache(FileChannel base) throws IOException {
+    private AtomicReference<ByteArrayOutputStream> appendBuffer;
+    private int appendOperations;
+    private Thread appendFlushThread;
+
+    FileCache(String name, FileChannel base) throws IOException {
+        this.name = name;
         this.base = base;
         this.size = base.size();
     }
@@ -47,7 +59,28 @@ public class FileCache extends FileBase 
         return this;
     }
 
+    boolean flush() throws IOException {
+        if (appendBuffer == null) {
+            return false;
+        }
+        synchronized (this) {
+            ByteArrayOutputStream newBuff = new ByteArrayOutputStream(APPEND_BUFFER_SIZE_INIT);
+            ByteArrayOutputStream buff = appendBuffer.getAndSet(newBuff);
+            if (buff.size() > 0) {
+                try {
+                    base.position(size - buff.size());
+                    base.write(ByteBuffer.wrap(buff.toByteArray()));
+                } catch (IOException e) {
+                    close();
+                    throw e;
+                }
+            }
+        }
+        return true;
+    }
+
     public int read(ByteBuffer dst) throws IOException {
+        flush();
         long readPos = (pos / BLOCK_SIZE) * BLOCK_SIZE;
         int off = (int) (pos - readPos);
         int len = BLOCK_SIZE - off;
@@ -77,6 +110,7 @@ public class FileCache extends FileBase 
     }
 
     public FileChannel truncate(long newSize) throws IOException {
+        flush();
         readCache.clear();
         base.truncate(newSize);
         pos = Math.min(pos, newSize);
@@ -85,8 +119,51 @@ public class FileCache extends FileBase 
     }
 
     public int write(ByteBuffer src) throws IOException {
+        if (readCache.size() > 0) {
+            readCache.clear();
+        }
+        // append operations are buffered, but
+        // only if there was at least one successful write operation
+        // (to detect trying to write to a read-only file and such early on)
+        // (in addition to that, the first few append operations are not buffered
+        // to avoid starting a thread unnecessarily)
+        if (APPEND_BUFFER && pos == size && ++appendOperations >= 4) {
+            int len = src.remaining();
+            if (len > APPEND_BUFFER_SIZE) {
+                flush();
+            } else {
+                if (appendBuffer == null) {
+                    ByteArrayOutputStream buff = new ByteArrayOutputStream(APPEND_BUFFER_SIZE_INIT);
+                    appendBuffer = new AtomicReference<ByteArrayOutputStream>(buff);
+                    appendFlushThread = new Thread("Flush " + name) {
+                        public void run() {
+                            try {
+                                do {
+                                    Thread.sleep(500);
+                                    if (flush()) {
+                                        continue;
+                                    }
+                                } while (!Thread.interrupted());
+                            } catch (Exception e) {
+                                // ignore
+                            }
+                        }
+                    };
+                    appendFlushThread.setDaemon(true);
+                    appendFlushThread.start();
+                }
+                ByteArrayOutputStream buff = appendBuffer.get();
+                if (buff.size() > APPEND_BUFFER_SIZE) {
+                    flush();
+                    buff = appendBuffer.get();
+                }
+                buff.write(src.array(), src.position(), len);
+                pos += len;
+                size += len;
+                return len;
+            }
+        }
         base.position(pos);
-        readCache.clear();
         int len = base.write(src);
         pos += len;
         size = Math.max(size, pos);
@@ -94,14 +171,25 @@ public class FileCache extends FileBase 
     }
 
     protected void implCloseChannel() throws IOException {
+        if (appendBuffer != null) {
+            appendFlushThread.interrupt();
+            try {
+                appendFlushThread.join();
+            } catch (InterruptedException e) {
+                // ignore
+            }
+            flush();
+        }
         base.close();
     }
 
     public void force(boolean metaData) throws IOException {
+        flush();
         base.force(metaData);
     }
 
     public FileLock tryLock(long position, long size, boolean shared) throws IOException {
+        flush();
         return base.tryLock(position, size, shared);
     }
 

Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/fs/FilePathCache.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/fs/FilePathCache.java?rev=1235674&r1=1235673&r2=1235674&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/fs/FilePathCache.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/fs/FilePathCache.java Wed Jan 25 08:24:04 2012
@@ -25,7 +25,7 @@ import java.nio.channels.FileChannel;
 public class FilePathCache extends FilePathWrapper {
 
     public FileChannel open(String mode) throws IOException {
-        return new FileCache(getBase().open(mode));
+        return new FileCache(getBase().name, getBase().open(mode));
     }
 
     public String getScheme() {

Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/fs/FileUtils.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/fs/FileUtils.java?rev=1235674&r1=1235673&r2=1235674&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/fs/FileUtils.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/fs/FileUtils.java Wed Jan 25 08:24:04 2012
@@ -367,5 +367,4 @@ public class FileUtils {
         } while (src.remaining() > 0);
     }
 
-
 }