diff options
| author | Luke Kanies <luke@madstop.com> | 2008-12-15 00:22:09 -0600 |
|---|---|---|
| committer | James Turnbull <james@lovedthanlost.net> | 2008-12-15 19:27:45 +1100 |
| commit | cf19bd8dea141a59cdff5a7f1edc56d3620ab0e2 (patch) | |
| tree | d921ad9b313ed11efbf6d301af478e61efccd155 | |
| parent | b966ea02a9deeb947bd6153c4cd7c53b1ddff3d8 (diff) | |
| download | puppet-cf19bd8dea141a59cdff5a7f1edc56d3620ab0e2.tar.gz puppet-cf19bd8dea141a59cdff5a7f1edc56d3620ab0e2.tar.xz puppet-cf19bd8dea141a59cdff5a7f1edc56d3620ab0e2.zip | |
Not using a temporary file when locking files for writing.
The temporary file was not actually useful, because we
could never really get atomic renames, for annoying,
complicated reasons.
This hopefully finally fixes #1812.
Signed-off-by: Luke Kanies <luke@madstop.com>
| -rw-r--r-- | lib/puppet/util/file_locking.rb | 15 | ||||
| -rwxr-xr-x | spec/integration/util/file_locking.rb | 6 | ||||
| -rwxr-xr-x | spec/unit/util/file_locking.rb | 43 |
3 files changed, 15 insertions, 49 deletions
diff --git a/lib/puppet/util/file_locking.rb b/lib/puppet/util/file_locking.rb index 80a0b2b0c..101ece308 100644 --- a/lib/puppet/util/file_locking.rb +++ b/lib/puppet/util/file_locking.rb @@ -21,6 +21,11 @@ module Puppet::Util::FileLocking tmpfile = file + ".tmp" unless mode + # It's far more likely that the file will be there than not, so it's + # better to stat once to check for existence and mode. + # If we can't stat, it's most likely because the file's not there, + # but could also be because the directory isn't readable, in which case + # we won't be able to write anyway. begin mode = File.stat(file).mode rescue @@ -31,15 +36,7 @@ module Puppet::Util::FileLocking Puppet::Util.sync(file).synchronize(Sync::EX) do File.open(file, "w", mode) do |rf| rf.lock_exclusive do |lrf| - File.open(tmpfile, "w", mode) do |tf| - yield tf - end - begin - File.rename(tmpfile, file) - rescue => detail - File.unlink(tmpfile) if File.exist?(tmpfile) - raise Puppet::Error, "Could not rename %s to %s: %s; file %s was unchanged" % [file, tmpfile, Thread.current.object_id, detail, file] - end + yield lrf end end end diff --git a/spec/integration/util/file_locking.rb b/spec/integration/util/file_locking.rb index f8e21ed6e..680b3d1ed 100755 --- a/spec/integration/util/file_locking.rb +++ b/spec/integration/util/file_locking.rb @@ -9,9 +9,9 @@ describe Puppet::Util::FileLocking do file = Tempfile.new("puppetspec") file.close!() file = file.path - File.open(file, "w") { |f| f.puts "starting" } - data = {:a => :b, :c => "A string", :d => "another string", :e => %w{an array of strings}} + File.open(file, "w") { |f| f.puts YAML.dump(data) } + threads = [] sync = Sync.new 9.times { |a| @@ -19,7 +19,7 @@ describe Puppet::Util::FileLocking do 9.times { |b| sync.synchronize(Sync::SH) { Puppet::Util::FileLocking.readlock(file) { |f| - YAML.load(f.read) + YAML.load(f.read).should == data } } sleep 0.01 diff --git a/spec/unit/util/file_locking.rb b/spec/unit/util/file_locking.rb index a8b0c1840..70003faa1 100755 --- a/spec/unit/util/file_locking.rb +++ b/spec/unit/util/file_locking.rb @@ -98,49 +98,18 @@ describe Puppet::Util::FileLocking do Puppet::Util::FileLocking.writelock('/file') end - it "should write to a temporary file" do + it "should allow the caller to write to the locked file" do fh = mock 'fh' File.expects(:open).yields fh lfh = mock 'locked_filehandle' - fh.expects(:lock_exclusive).yields lfh + fh.expects(:lock_exclusive).yields(lfh) - tf = mock 'tmp_filehandle' - File.expects(:open).with { |path, *args| path == "/file.tmp" }.yields tf + lfh.expects(:print).with "foo" - result = nil - File.stubs(:rename) - Puppet::Util::FileLocking.writelock('/file') { |f| result = f } - result.should equal(tf) - end - - it "should rename the temporary file to the normal file" do - fh = stub 'fh' - fh.stubs(:lock_exclusive).yields fh - File.stubs(:open).yields fh - - File.expects(:rename).with("/file.tmp", "/file") - Puppet::Util::FileLocking.writelock('/file') { |f| } - end - - it "should fail if it cannot rename the file" do - fh = stub 'fh' - fh.stubs(:lock_exclusive).yields fh - File.stubs(:open).yields fh - - File.expects(:rename).with("/file.tmp", "/file").raises(RuntimeError) - lambda { Puppet::Util::FileLocking.writelock('/file') { |f| } }.should raise_error(Puppet::Error) - end - - it "should remove the temporary file if the rename fails" do - fh = stub 'fh' - fh.stubs(:lock_exclusive).yields fh - File.stubs(:open).yields fh - - File.expects(:rename).with("/file.tmp", "/file").raises(RuntimeError) - File.expects(:exist?).with("/file.tmp").returns true - File.expects(:unlink).with("/file.tmp") - lambda { Puppet::Util::FileLocking.writelock('/file') { |f| } }.should raise_error(Puppet::Error) + Puppet::Util::FileLocking.writelock('/file') do |f| + f.print "foo" + end end end end |
