Skip to content
This repository
Browse code

Merge pull request #157 from github/atomic-object-writes

Atomic object writes
  • Loading branch information...
commit 58621d933b4aa846e87f943b48f3f91b65dfb191 2 parents 75cf040 + cdf0fdb
Ryan Tomayko authored February 23, 2013

Showing 1 changed file with 20 additions and 3 deletions. Show diff stats Hide diff stats

  1. 23  lib/grit/git-ruby/internal/loose.rb
23  lib/grit/git-ruby/internal/loose.rb
@@ -12,6 +12,7 @@
12 12
 require 'zlib'
13 13
 require 'digest/sha1'
14 14
 require 'grit/git-ruby/internal/raw_object'
  15
+require 'tempfile'
15 16
 
16 17
 module Grit
17 18
   module GitRuby
@@ -60,6 +61,24 @@ def get_raw_object(buf)
60 61
           return RawObject.new(type, content)
61 62
         end
62 63
 
  64
+        # write an object to a temporary file, then atomically rename it
  65
+        # into place; this ensures readers never see a half-written file
  66
+        def safe_write(path, content)
  67
+          Tempfile.open("tmp_obj_", File.dirname(path), :opt => "wb") do |f|
  68
+            f.write content
  69
+            f.fsync
  70
+            f.close
  71
+            begin
  72
+              File.link(f.path, path)
  73
+            rescue Errno::EEXIST
  74
+              # The path already exists; we raced with another process,
  75
+              # but it's OK, because by definition the content is the
  76
+              # same. So we can just ignore the error.
  77
+            end
  78
+            f.unlink
  79
+          end
  80
+        end
  81
+
63 82
         # currently, I'm using the legacy format because it's easier to do
64 83
         # this function takes content and a type and writes out the loose object and returns a sha
65 84
         def put_raw_object(content, type)
@@ -76,9 +95,7 @@ def put_raw_object(content, type)
76 95
             content = Zlib::Deflate.deflate(store)
77 96
 
78 97
             FileUtils.mkdir_p(@directory+'/'+sha1[0...2])
79  
-            File.open(path, 'wb') do |f|
80  
-              f.write content
81  
-            end
  98
+            safe_write(path, content)
82 99
           end
83 100
           return sha1
84 101
         end

0 notes on commit 58621d9

Please sign in to comment.
Something went wrong with that request. Please try again.