diff options
author | nobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2004-07-01 14:15:38 +0000 |
---|---|---|
committer | nobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2004-07-01 14:15:38 +0000 |
commit | 7800d8ad76bfda9884f5127c576ba08b1fe82583 (patch) | |
tree | 60f53b0878437539143899edaaa35a54635b3182 /lib/pstore.rb | |
parent | c7bd86ed15eb4baf2dcb9a7b732891de4619d88a (diff) |
* lib/pstore.rb (transaction): safer backup scheme. [ruby-list:39102]
* lib/pstore.rb (commit_new): use FileUtils.copy_stream for Cygwin.
[ruby-dev:23157]
* lib/pstore.rb (transaction): allow overriding dump and load.
[ruby-dev:23567]
* lib/pstore.rb (PStore#transaction): get rid of opening in write mode
when read only transaction. [ruby-dev:23842]
* lib/yaml/store.rb: follow lib/pstore.rb's change.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8@6562 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib/pstore.rb')
-rw-r--r-- | lib/pstore.rb | 98 |
1 files changed, 63 insertions, 35 deletions
diff --git a/lib/pstore.rb b/lib/pstore.rb index 93795495fc..c4c6dd56a5 100644 --- a/lib/pstore.rb +++ b/lib/pstore.rb @@ -12,7 +12,7 @@ # p db["root"] # end -require "ftools" +require "fileutils" require "digest/md5" class PStore @@ -35,7 +35,11 @@ class PStore def in_transaction raise PStore::Error, "not in transaction" unless @transaction end - private :in_transaction + def in_transaction_wr() + in_transaction() + raise PStore::Error, "in read-only transaction" if @rdonly + end + private :in_transaction, :in_transaction_wr def [](name) in_transaction @@ -52,11 +56,11 @@ class PStore self[name] end def []=(name, value) - in_transaction + in_transaction_wr() @table[name] = value end def delete(name) - in_transaction + in_transaction_wr() @table.delete name end @@ -86,27 +90,35 @@ class PStore def transaction(read_only=false) raise PStore::Error, "nested transaction" if @transaction begin + @rdonly = read_only + @abort = false @transaction = true value = nil - backup = @filename+"~" - begin - file = File::open(@filename, read_only ? "rb" : "rb+") - orig = true - rescue Errno::ENOENT - raise if read_only - file = File::open(@filename, "wb+") + new_file = @filename + ".new" + + content = nil + unless read_only + file = File.open(@filename, File::RDWR | File::CREAT) + file.flock(File::LOCK_EX) + commit_new(file) if FileTest.exist?(new_file) + content = file.read() + else + file = File.open(@filename, File::RDONLY) + file.flock(File::LOCK_SH) + content = (File.read(new_file) rescue file.read()) end - file.flock(read_only ? File::LOCK_SH : File::LOCK_EX) - if read_only - @table = Marshal::load(file) - elsif orig and (content = file.read) != "" - @table = Marshal::load(content) - size = content.size - md5 = Digest::MD5.digest(content) - content = nil # unreference huge data + + if content != "" + @table = load(content) + if !read_only + size = content.size + md5 = Digest::MD5.digest(content) + end else @table = {} end + content = nil # unreference huge data + begin catch(:pstore_abort_transaction) do value = yield(self) @@ -116,24 +128,17 @@ class PStore raise ensure if !read_only and !@abort - file.rewind - content = Marshal::dump(@table) + tmp_file = @filename + ".tmp" + content = dump(@table) if !md5 || size != content.size || md5 != Digest::MD5.digest(content) - File::copy @filename, backup - begin - file.write(content) - file.truncate(file.pos) - content = nil # unreference huge data - rescue - File::rename backup, @filename if File::exist?(backup) - raise - end - end - end - if @abort and !orig - File.unlink(@filename) + File.open(tmp_file, "w") {|t| + t.write(content) + } + File.rename(tmp_file, new_file) + commit_new(file) + end + content = nil # unreference huge data end - @abort = false end ensure @table = nil @@ -142,6 +147,29 @@ class PStore end value end + + def dump(table) + Marshal::dump(table) + end + + def load(content) + Marshal::load(content) + end + + def load_file(file) + Marshal::load(file) + end + + private + def commit_new(f) + f.truncate(0) + f.rewind + new_file = @filename + ".new" + File.open(new_file) do |nf| + FileUtils.copy_stream(nf, f) + end + File.unlink(new_file) + end end if __FILE__ == $0 |