Project

General

Profile

Feature #5248 » patch.diff

Glass_saga (Masaki Matsushita), 12/20/2011 03:22 PM

View differences:

lib/pstore.rb
#
# See PStore for documentation.
require "fileutils"
require "digest/md5"
require "thread"
#
# PStore implements a file based persistence mechanism based on a Hash. User
......
# Raises PStore::Error if the calling code is not in a PStore#transaction or
# if the code is in a read-only PStore#transaction.
#
def in_transaction_wr()
in_transaction()
def in_transaction_wr
in_transaction
raise PStore::Error, "in read-only transaction" if @rdonly
end
private :in_transaction, :in_transaction_wr
......
# be read-only. It will raise PStore::Error if called at any other time.
#
def []=(name, value)
in_transaction_wr()
in_transaction_wr
@table[name] = value
end
#
......
# be read-only. It will raise PStore::Error if called at any other time.
#
def delete(name)
in_transaction_wr()
in_transaction_wr
@table.delete name
end
......
if read_only
begin
table = load(file)
if !table.is_a?(Hash)
raise Error, "PStore file seems to be corrupted."
end
raise Error, "PStore file seems to be corrupted." unless table.is_a?(Hash)
rescue EOFError
# This seems to be a newly-created file.
table = {}
......
# This seems to be a newly-created file.
table = {}
checksum = empty_marshal_checksum
size = empty_marshal_data.size
size = empty_marshal_data.bytesize
else
table = load(data)
checksum = Digest::MD5.digest(data)
size = data.size
if !table.is_a?(Hash)
raise Error, "PStore file seems to be corrupted."
end
size = data.bytesize
raise Error, "PStore file seems to be corrupted." unless table.is_a?(Hash)
end
data.replace(EMPTY_STRING)
[table, checksum, size]
......
end
def on_windows?
is_windows = RUBY_PLATFORM =~ /mswin/ ||
RUBY_PLATFORM =~ /mingw/ ||
RUBY_PLATFORM =~ /bccwin/ ||
RUBY_PLATFORM =~ /wince/
is_windows = RUBY_PLATFORM =~ /mswin|mingw|bccwin|wince/
self.class.__send__(:define_method, :on_windows?) do
is_windows
end
is_windows
end
# Check whether Marshal.dump supports the 'canonical' option. This option
# makes sure that Marshal.dump always dumps data structures in the same order.
# This is important because otherwise, the checksums that we generate may differ.
def marshal_dump_supports_canonical_option?
begin
Marshal.dump(nil, -1, true)
result = true
rescue
result = false
end
self.class.instance_method(:marshal_dump_supports_canonical_option?)
self.class.__send__(:define_method, :marshal_dump_supports_canonical_option?) do
result
end
result
end
def save_data(original_checksum, original_file_size, file)
# We only want to save the new data if the size or checksum has changed.
# This results in less filesystem calls, which is good for performance.
if marshal_dump_supports_canonical_option?
new_data = Marshal.dump(@table, -1, true)
else
new_data = dump(@table)
end
new_checksum = Digest::MD5.digest(new_data)
new_data = dump(@table)
if new_data.size != original_file_size || new_checksum != original_checksum
if new_data.size != original_file_size || Digest::MD5.digest(new_data) != original_checksum
if @ultra_safe && !on_windows?
# Windows doesn't support atomic file renames.
save_data_with_atomic_file_rename_strategy(new_data, file)
......
def save_data_with_fast_strategy(data, file)
file.rewind
file.truncate(0)
file.write(data)
file.truncate(data.bytesize)
end
# This method is just a wrapped around Marshal.dump
# to allow subclass overriding used in YAML::Store.
def dump(table) # :nodoc:
......
def empty_marshal_data
EMPTY_MARSHAL_DATA
end
def empty_marshal_checksum
EMPTY_MARSHAL_CHECKSUM
end
......
# :enddoc:
if __FILE__ == $0
if __FILE__ == $PROGRAM_NAME
db = PStore.new("/tmp/foo")
db.transaction do
p db.roots
(2-2/4)