]> source.dussan.org Git - jgit.git/commitdiff
Support core.fsyncRefFiles option 84/1884/2
authorShawn O. Pearce <spearce@spearce.org>
Thu, 11 Nov 2010 01:24:16 +0000 (17:24 -0800)
committerShawn O. Pearce <spearce@spearce.org>
Fri, 12 Nov 2010 21:38:04 +0000 (13:38 -0800)
If core.fsyncRefFiles is set to true, fsync is used whenever a
reference file is updated, ensuring the file contents are also
written to disk.  This can help to prevent empty ref files after
a system crash when using a filesystem such as HFS+ where data
writes may be delayed.

Change-Id: Ie508a974da50f63b0409c38afe68772322dc19f1
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
org.eclipse.jgit/src/org/eclipse/jgit/storage/file/LockFile.java
org.eclipse.jgit/src/org/eclipse/jgit/storage/file/RefDirectory.java
org.eclipse.jgit/src/org/eclipse/jgit/storage/file/RefDirectoryUpdate.java
org.eclipse.jgit/src/org/eclipse/jgit/storage/file/WriteConfig.java

index 1a4952ad0f1520dd1ede37ec2d6561e2bd0c7be4..a794ec330241acb45d2156b5633756613555cb09 100644 (file)
@@ -51,6 +51,9 @@ import java.io.FileOutputStream;
 import java.io.FilenameFilter;
 import java.io.IOException;
 import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.channels.Channels;
+import java.nio.channels.FileChannel;
 import java.nio.channels.FileLock;
 import java.nio.channels.OverlappingFileLockException;
 import java.text.MessageFormat;
@@ -92,6 +95,8 @@ public class LockFile {
 
        private boolean needStatInformation;
 
+       private boolean fsync;
+
        private long commitLastModified;
 
        private final FS fs;
@@ -191,10 +196,21 @@ public class LockFile {
                try {
                        final FileInputStream fis = new FileInputStream(ref);
                        try {
-                               final byte[] buf = new byte[2048];
-                               int r;
-                               while ((r = fis.read(buf)) >= 0)
-                                       os.write(buf, 0, r);
+                               if (fsync) {
+                                       FileChannel in = fis.getChannel();
+                                       long pos = 0;
+                                       long cnt = in.size();
+                                       while (0 < cnt) {
+                                               long r = os.getChannel().transferFrom(in, pos, cnt);
+                                               pos += r;
+                                               cnt -= r;
+                                       }
+                               } else {
+                                       final byte[] buf = new byte[2048];
+                                       int r;
+                                       while ((r = fis.read(buf)) >= 0)
+                                               os.write(buf, 0, r);
+                               }
                        } finally {
                                fis.close();
                        }
@@ -251,8 +267,15 @@ public class LockFile {
        public void write(final byte[] content) throws IOException {
                requireLock();
                try {
-                       os.write(content);
-                       os.flush();
+                       if (fsync) {
+                               FileChannel fc = os.getChannel();
+                               ByteBuffer buf = ByteBuffer.wrap(content);
+                               while (0 < buf.remaining())
+                                       fc.write(buf);
+                               fc.force(true);
+                       } else {
+                               os.write(content);
+                       }
                        fLck.release();
                        os.close();
                        os = null;
@@ -279,34 +302,43 @@ public class LockFile {
         */
        public OutputStream getOutputStream() {
                requireLock();
+
+               final OutputStream out;
+               if (fsync)
+                       out = Channels.newOutputStream(os.getChannel());
+               else
+                       out = os;
+
                return new OutputStream() {
                        @Override
                        public void write(final byte[] b, final int o, final int n)
                                        throws IOException {
-                               os.write(b, o, n);
+                               out.write(b, o, n);
                        }
 
                        @Override
                        public void write(final byte[] b) throws IOException {
-                               os.write(b);
+                               out.write(b);
                        }
 
                        @Override
                        public void write(final int b) throws IOException {
-                               os.write(b);
+                               out.write(b);
                        }
 
                        @Override
                        public void flush() throws IOException {
-                               os.flush();
+                               out.flush();
                        }
 
                        @Override
                        public void close() throws IOException {
                                try {
-                                       os.flush();
+                                       out.flush();
+                                       if (fsync)
+                                               os.getChannel().force(true);
                                        fLck.release();
-                                       os.close();
+                                       out.close();
                                        os = null;
                                } catch (IOException ioe) {
                                        unlock();
@@ -339,6 +371,16 @@ public class LockFile {
                needStatInformation = on;
        }
 
+       /**
+        * Request that {@link #commit()} force dirty data to the drive.
+        *
+        * @param on
+        *            true if dirty data should be forced to the drive.
+        */
+       public void setFSync(final boolean on) {
+               fsync = on;
+       }
+
        /**
         * Wait until the lock file information differs from the old file.
         * <p>
index 96c8361adb2e12f515798e8a17111c224607d56e..2af7ca3e6dfb40fd8f29ae2599512622466d1b5c 100644 (file)
@@ -67,6 +67,8 @@ import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStreamReader;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
 import java.text.MessageFormat;
 import java.util.Arrays;
 import java.util.LinkedList;
@@ -606,6 +608,7 @@ public class RefDirectory extends RefDatabase {
                        write = false;
 
                if (write) {
+                       WriteConfig wc = getRepository().getConfig().get(WriteConfig.KEY);
                        FileOutputStream out;
                        try {
                                out = new FileOutputStream(log, true);
@@ -618,7 +621,15 @@ public class RefDirectory extends RefDatabase {
                                out = new FileOutputStream(log, true);
                        }
                        try {
-                               out.write(rec);
+                               if (wc.getFSyncRefFiles()) {
+                                       FileChannel fc = out.getChannel();
+                                       ByteBuffer buf = ByteBuffer.wrap(rec);
+                                       while (0 < buf.remaining())
+                                               fc.write(buf);
+                                       fc.force(true);
+                               } else {
+                                       out.write(rec);
+                               }
                        } finally {
                                out.close();
                        }
@@ -757,6 +768,7 @@ public class RefDirectory extends RefDatabase {
                        @Override
                        protected void writeFile(String name, byte[] content)
                                        throws IOException {
+                               lck.setFSync(true);
                                lck.setNeedStatInformation(true);
                                try {
                                        lck.write(content);
index a9f054837bcd52ac44c235cf1fbf56312cdfe593..109960df2b826bb1092c0d766c754da014fe800a 100644 (file)
@@ -99,6 +99,10 @@ class RefDirectoryUpdate extends RefUpdate {
 
        @Override
        protected Result doUpdate(final Result status) throws IOException {
+               WriteConfig wc = database.getRepository().getConfig()
+                               .get(WriteConfig.KEY);
+
+               lock.setFSync(wc.getFSyncRefFiles());
                lock.setNeedStatInformation(true);
                lock.write(getNewObjectId());
 
@@ -143,6 +147,10 @@ class RefDirectoryUpdate extends RefUpdate {
 
        @Override
        protected Result doLink(final String target) throws IOException {
+               WriteConfig wc = database.getRepository().getConfig()
+                               .get(WriteConfig.KEY);
+
+               lock.setFSync(wc.getFSyncRefFiles());
                lock.setNeedStatInformation(true);
                lock.write(encode(RefDirectory.SYMREF + target + '\n'));
 
index 1f28d8b75f821b8e6a3950afac809dca3ee5e61a..fd467a5554526791ff32907427d93309e81f2335 100644 (file)
@@ -59,9 +59,12 @@ class WriteConfig {
 
        private final boolean fsyncObjectFiles;
 
+       private final boolean fsyncRefFiles;
+
        private WriteConfig(final Config rc) {
                compression = rc.get(CoreConfig.KEY).getCompression();
                fsyncObjectFiles = rc.getBoolean("core", "fsyncobjectfiles", false);
+               fsyncRefFiles = rc.getBoolean("core", "fsyncreffiles", false);
        }
 
        int getCompression() {
@@ -71,4 +74,8 @@ class WriteConfig {
        boolean getFSyncObjectFiles() {
                return fsyncObjectFiles;
        }
+
+       boolean getFSyncRefFiles() {
+               return fsyncRefFiles;
+       }
 }