mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* 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
This commit is contained in:
parent
c7bd86ed15
commit
7800d8ad76
3 changed files with 100 additions and 103 deletions
|
@ -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
|
||||
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
|
||||
if @abort and !orig
|
||||
File.unlink(@filename)
|
||||
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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue