lib/daybreak/db.rb in daybreak-0.1.1 vs lib/daybreak/db.rb in daybreak-0.1.2

- old
+ new

@@ -12,14 +12,15 @@ # @param default the default value to store and return when a key is # not yet in the database. # @yield [key] a block that will return the default value to store. # @yieldparam [String] key the key to be stored. def initialize(file, default=nil, &blk) + @table = {} @file_name = file - reset! - @default = default - @default = blk if block_given? + @reader = Reader.new(@file_name) + @writer = Writer.new(@file_name) + @default = block_given? ? blk : default read! end # Set a key in the database to be written at some future date. If the data # needs to be persisted immediately, call <tt>db.set(key, value, true)</tt>. @@ -62,26 +63,21 @@ def [](key) key = key.to_s if @table.has_key? key @table[key] elsif default? - if @default.is_a? Proc - value = @default.call(key) - else - value = @default - end - set key, value + set key, Proc === @default ? @default.call(key) : @default end end alias_method :get, :"[]" # Iterate over the key, value pairs in the database. # @yield [key, value] blk the iterator for each key value pair. # @yieldparam [String] key the key. # @yieldparam value the value from the database. - def each(&blk) - keys.each { |k| blk.call(k, get(k)) } + def each + keys.each { |k| yield(k, get(k)) } end # Does this db have a default value. def default? !@default.nil? @@ -102,10 +98,11 @@ # Return the number of stored items. # @return [Integer] def length @table.keys.length end + alias_method :size, :length # Serialize the data for writing to disk, if you don't want to use <tt>Marshal</tt> # overwrite this method. # @param value the value to be serialized # @return [String] @@ -119,78 +116,66 @@ # @return [String] def parse(value) Marshal.load(value) end - # Reset and empty the database file. + # Empty the database file. def empty! @writer.truncate! - close! - reset! + @table.clear read! end alias_method :clear, :empty! # Force all queued commits to be written to disk. def flush! @writer.flush! end - # Reset the state of the database, you should call <tt>read!</tt> after calling this. - def reset! - @table = {} - @writer = Daybreak::Writer.new(@file_name) - @reader = Daybreak::Reader.new(@file_name) - end - # Close the database for reading and writing. def close! @writer.close! - @reader.close! end # Compact the database to remove stale commits and reduce the file size. def compact! - # Create a new temporary file - tmp_file = Tempfile.new File.basename(@file_name) - copy_db = self.class.new tmp_file.path + # Create a new temporary database + tmp_file = @file_name + "-#{$$}-#{Thread.current.object_id}" + copy_db = self.class.new tmp_file # Copy the database key by key into the temporary table - each do |key| + each do |key, value| copy_db.set(key, get(key)) end copy_db.close! - # Empty this database - empty! close! # Move the copy into place - tmp_file.close - FileUtils.mv tmp_file.path, @file_name - tmp_file.unlink + File.rename tmp_file, @file_name - # Reset this database - reset! + # Reopen this database + @writer = Writer.new(@file_name) + @table.clear read! end # Read all values from the log file. If you want to check for changed data # call this again. def read! - @reader.read do |record| - if record.deleted? - @table.delete record.key + @reader.read do |(key, data, deleted)| + if deleted + @table.delete key else - @table[record.key] = parse(record.data) + @table[key] = parse(data) end end end private def write(key, value, sync = false, delete = false) - @writer.write(Record.new(key, serialize(value), delete)) + @writer.write([key, serialize(value), delete]) flush! if sync end end end