transaction(read_only=false)
public
Opens a new transaction for the data store. Code
executed inside a block passed to this method may read and write data to
and from the data store file.
At the end of the block, changes are committed to the data store
automatically. You may exit the transaction early with a call to either
PStore#commit or PStore#abort. See those methods for details
about how changes are handled. Raising an uncaught Exception in the block is equivalent to calling
PStore#abort.
If read_only is set to true, you will only be allowed to
read from the data store during the transaction and any attempts to change
the data will raise a PStore::Error.
Note that PStore does not support nested
transactions.
Show source
def transaction(read_only=false)
raise PStore::Error, "nested transaction" if @transaction
begin
@rdonly = read_only
@abort = false
@transaction = true
value = nil
new_file = @filename + ".new"
content = nil
unless read_only
file = File.open(@filename, RDWR_ACCESS)
file.flock(File::LOCK_EX)
commit_new(file) if FileTest.exist?(new_file)
content = file.read()
else
begin
file = File.open(@filename, RD_ACCESS)
file.flock(File::LOCK_SH)
content = (File.open(new_file, RD_ACCESS) {|n| n.read} rescue file.read())
rescue Errno::ENOENT
content = ""
end
end
if content != ""
@table = load(content)
if !read_only
size = content.size
md5 = Digest::MD5.digest(content)
end
else
@table = {}
end
content = nil
begin
catch(:pstore_abort_transaction) do
value = yield(self)
end
rescue Exception
@abort = true
raise
ensure
if !read_only and !@abort
tmp_file = @filename + ".tmp"
content = dump(@table)
if !md5 || size != content.size || md5 != Digest::MD5.digest(content)
File.open(tmp_file, WR_ACCESS) {|t| t.write(content)}
File.rename(tmp_file, new_file)
commit_new(file)
end
content = nil
end
end
ensure
@table = nil
@transaction = false
file.close if file
end
value
end