Feature #5976 ยป patch.diff
lib/pstore.rb | ||
---|---|---|
@filename = file
|
||
@abort = false
|
||
@ultra_safe = false
|
||
@modified = false
|
||
@thread_safe = thread_safe
|
||
@lock = Mutex.new
|
||
end
|
||
... | ... | |
def in_transaction_wr
|
||
in_transaction
|
||
raise PStore::Error, "in read-only transaction" if @rdonly
|
||
@modified = true
|
||
end
|
||
private :in_transaction, :in_transaction_wr
|
||
... | ... | |
@lock.synchronize do
|
||
@rdonly = read_only
|
||
@abort = false
|
||
@modified = false
|
||
file = open_and_lock_file(@filename, read_only)
|
||
if file
|
||
begin
|
||
@table, checksum, original_data_size = load_data(file, read_only)
|
||
@table = load_data(file)
|
||
catch(:pstore_abort_transaction) do
|
||
value = yield(self)
|
||
end
|
||
if !@abort && !read_only
|
||
save_data(checksum, original_data_size, file)
|
||
save_data(file)
|
||
end
|
||
ensure
|
||
file.close if !file.closed?
|
||
... | ... | |
end
|
||
private
|
||
# Constant for relieving Ruby's garbage collector.
|
||
# Constants for compatibility.
|
||
EMPTY_STRING = ""
|
||
EMPTY_MARSHAL_DATA = Marshal.dump({})
|
||
EMPTY_MARSHAL_CHECKSUM = Digest::MD5.digest(EMPTY_MARSHAL_DATA)
|
||
... | ... | |
end
|
||
# Load the given PStore file.
|
||
# If +read_only+ is true, the unmarshalled Hash will be returned.
|
||
# If +read_only+ is false, a 3-tuple will be returned: the unmarshalled
|
||
# Hash, an MD5 checksum of the data, and the size of the data.
|
||
def load_data(file, read_only)
|
||
if read_only
|
||
begin
|
||
table = load(file)
|
||
raise Error, "PStore file seems to be corrupted." unless table.is_a?(Hash)
|
||
rescue EOFError
|
||
# This seems to be a newly-created file.
|
||
table = {}
|
||
end
|
||
table
|
||
else
|
||
data = file.read
|
||
if data.empty?
|
||
# This seems to be a newly-created file.
|
||
table = {}
|
||
checksum = empty_marshal_checksum
|
||
size = empty_marshal_data.bytesize
|
||
else
|
||
table = load(data)
|
||
checksum = Digest::MD5.digest(data)
|
||
size = data.bytesize
|
||
raise Error, "PStore file seems to be corrupted." unless table.is_a?(Hash)
|
||
end
|
||
data.replace(EMPTY_STRING)
|
||
[table, checksum, size]
|
||
# The unmarshalled Hash will be returned.
|
||
def load_data(file)
|
||
begin
|
||
table = load(file)
|
||
raise Error, "PStore file seems to be corrupted." unless table.is_a?(Hash)
|
||
rescue EOFError
|
||
# This seems to be a newly-created file.
|
||
table = {}
|
||
end
|
||
table
|
||
end
|
||
def on_windows?
|
||
... | ... | |
is_windows
|
||
end
|
||
def save_data(original_checksum, original_file_size, file)
|
||
def save_data(file)
|
||
new_data = dump(@table)
|
||
if new_data.bytesize != original_file_size || Digest::MD5.digest(new_data) != original_checksum
|
||
if @modified
|
||
if @ultra_safe && !on_windows?
|
||
# Windows doesn't support atomic file renames.
|
||
save_data_with_atomic_file_rename_strategy(new_data, file)
|
||
... | ... | |
end
|
||
end
|
||
new_data.replace(EMPTY_STRING)
|
||
new_data.clear
|
||
end
|
||
def save_data_with_atomic_file_rename_strategy(data, file)
|