Class: Amp::Journal
Overview
Provides a journal interface so when a large number of transactions are occurring, and any one could fail, we can rollback the changes.
Constant Summary collapse
- DEFAULT_OPTS =
{:reporter => StandardErrorReporter, :after_close => nil}
Instance Attribute Summary collapse
-
#after_close ⇒ Object
Returns the value of attribute after_close.
-
#journal ⇒ Object
Returns the value of attribute journal.
-
#report ⇒ Object
Returns the value of attribute report.
Class Method Summary collapse
-
.rollback(file) ⇒ Object
If we crashed during an abort, the journal file is gonna be sitting aorund somewhere.
- .start(file, opts = DEFAULT_OPTS) ⇒ Amp::Journal
Instance Method Summary collapse
-
#abort ⇒ Object
Abort, abort! abandon ship! This rolls back any changes we’ve made during the current journalling session.
-
#add_entry(array) ⇒ Object
(also: #<<)
Adds an entry to the journal.
-
#close ⇒ Object
Closes up the journal.
-
#delete ⇒ Object
Kills the journal - used when shit goes down and we gotta give up on the transactions.
-
#find_file(file) ⇒ Hash
(also: #find)
Finds the entry for a given file’s path.
-
#initialize(reporter = StandardErrorReporter, journal = "journal#{rand(10000)}", createmode = nil, &after_close) ⇒ Journal
constructor
Initializes the journal to get ready for some transactions.
-
#nest ⇒ Object
No godly idea what this is for.
-
#replace(file, offset, data = nil) ⇒ Object
(also: #update)
Updates an entry’s data, based on the filename.
-
#running? ⇒ Boolean
Is the journal running right now?.
Constructor Details
#initialize(reporter = StandardErrorReporter, journal = "journal#{rand(10000)}", createmode = nil, &after_close) ⇒ Journal
Initializes the journal to get ready for some transactions.
42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/amp/repository/journal.rb', line 42 def initialize(reporter=StandardErrorReporter, journal="journal#{rand(10000)}", createmode=nil, &after_close) @count = 1 @reporter = reporter @after_close = after_close @entries = [] @map = {} @journal_file = journal @file = open(@journal_file, "w") FileUtils.chmod(createmode & 0666, @journal_file) unless createmode.nil? end |
Instance Attribute Details
#after_close ⇒ Object
Returns the value of attribute after_close.
14 15 16 |
# File 'lib/amp/repository/journal.rb', line 14 def after_close @after_close end |
#journal ⇒ Object
Returns the value of attribute journal.
14 15 16 |
# File 'lib/amp/repository/journal.rb', line 14 def journal @journal end |
#report ⇒ Object
Returns the value of attribute report.
14 15 16 |
# File 'lib/amp/repository/journal.rb', line 14 def report @report end |
Class Method Details
.rollback(file) ⇒ Object
If we crashed during an abort, the journal file is gonna be sitting aorund somewhere. So, we should rollback any changes it left lying around.
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 |
# File 'lib/amp/repository/journal.rb', line 179 def self.rollback(file) files = {} fp = open(file) fp.each_line do |line| file, offset = line.split("\0") files[file] = offset.to_i end fp.close files.each do |file, offset| if o > 0 fp = open(file, "a") fp.truncate o.to_i fp.close else fp = open(f) fn = fp.path fp.close FileUtils.safe_unlink fn end end FileUtils.safe_unlink file end |
.start(file, opts = DEFAULT_OPTS) ⇒ Amp::Journal
18 19 20 21 22 23 24 25 26 27 28 29 30 |
# File 'lib/amp/repository/journal.rb', line 18 def self.start(file, opts=DEFAULT_OPTS) journal = Journal.new opts[:reporter], file, &opts[:after_close] if block_given? begin yield journal ensure journal.close end end journal end |
Instance Method Details
#abort ⇒ Object
Abort, abort! abandon ship! This rolls back any changes we’ve made during the current journalling session.
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
# File 'lib/amp/repository/journal.rb', line 157 def abort return unless @entries && @entries.any? @reporter.report "transaction abort!\n" @entries.each do |hash| file, offset = hash[:file], hash[:offset] begin fp = open(File.join(".hg","store",file), "a") fp.truncate offset fp.close rescue @reporter.report "Failed to truncate #{File.join(".hg","store",file)}\n" end end @entries = [] @reporter.report "rollback completed\n" end |
#add_entry(array) ⇒ Object Also known as: <<
Adds an entry to the journal. Since all our files are just being appended to all the time, all we really need is to keep track of how long the file was when we last knew it to be safe. In other words, if the file started off at 20 bytes, then an error happened, we just truncate it to 20 bytes.
All params should be contained in the array
77 78 79 80 81 82 83 84 85 86 |
# File 'lib/amp/repository/journal.rb', line 77 def add_entry(array) file, offset, data = array[0], array[1], array[2] return if @map[file] @entries << {:file => file, :offset => offset, :data => data} @map[file] = @entries.size - 1 # tell the journal how to truncate this revision @file.write("#{file}\0#{offset}\n") @file.flush end |
#close ⇒ Object
Closes up the journal. Will call the after_close proc passed during instantiation.
141 142 143 144 145 146 147 148 149 150 151 152 |
# File 'lib/amp/repository/journal.rb', line 141 def close @count -= 1 return if @count != 0 @file.close @entries = [] if @after_close @after_close.call else FileUtils.safe_unlink(@journal_file) end @journal_file = nil end |
#delete ⇒ Object
Kills the journal - used when shit goes down and we gotta give up on the transactions.
58 59 60 61 62 63 64 |
# File 'lib/amp/repository/journal.rb', line 58 def delete if @journal_file abort if @entries.any? @file.close FileUtils.safe_unlink @journal_file end end |
#find_file(file) ⇒ Hash Also known as: find
Finds the entry for a given file’s path
97 98 99 100 |
# File 'lib/amp/repository/journal.rb', line 97 def find_file(file) return @entries[@map[file]] if @map[file] nil end |
#nest ⇒ Object
No godly idea what this is for
127 128 129 130 |
# File 'lib/amp/repository/journal.rb', line 127 def nest @count += 1 self end |
#replace(file, offset, data = nil) ⇒ Object Also known as: update
Updates an entry’s data, based on the filename. The file must already have been journaled.
113 114 115 116 117 118 119 |
# File 'lib/amp/repository/journal.rb', line 113 def replace(file, offset, data=nil) raise IndexError.new("journal lookup failed #{file}") unless @map[file] index = @map[file] @entries[index] = {:file => file, :offset => offset, :data => data} @file.write("#{file}\0#{offset}\n") @file.flush end |
#running? ⇒ Boolean
Is the journal running right now?
134 135 136 |
# File 'lib/amp/repository/journal.rb', line 134 def running? @count > 0 end |