Class: PEROBS::FixedSizeBlobFile
- Inherits:
-
Object
- Object
- PEROBS::FixedSizeBlobFile
- Defined in:
- lib/perobs/FixedSizeBlobFile.rb
Overview
This class implements persistent storage space for fixed size data blobs. The blobs can be stored and retrieved and can be deleted again. The FixedSizeBlobFile manages the storage of the blobs and free storage spaces. The files grows and shrinks as needed. A blob is referenced by its address.
Instance Method Summary collapse
-
#clear ⇒ Object
Delete all data.
-
#close ⇒ Object
Close the blob file.
-
#delete_blob(address) ⇒ Object
Delete the blob at the given address.
- #empty? ⇒ Boolean
-
#free_address ⇒ Fixnum
Return the address of a free blob storage space.
-
#initialize(dir, name, entry_bytes) ⇒ FixedSizeBlobFile
constructor
Create a new stack file in the given directory with the given file name.
-
#open ⇒ Object
Open the blob file.
-
#retrieve_blob(address) ⇒ String
Retrieve a blob from the given address.
-
#store_blob(address, bytes) ⇒ Object
Store the given byte blob at the specified address.
-
#sync ⇒ Object
Flush out all unwritten data.
Constructor Details
#initialize(dir, name, entry_bytes) ⇒ FixedSizeBlobFile
Create a new stack file in the given directory with the given file name.
44 45 46 47 48 49 |
# File 'lib/perobs/FixedSizeBlobFile.rb', line 44 def initialize(dir, name, entry_bytes) @file_name = File.join(dir, name + '.blobs') @entry_bytes = entry_bytes @free_list = StackFile.new(dir, name + '-freelist', 8) @f = nil end |
Instance Method Details
#clear ⇒ Object
Delete all data.
92 93 94 95 96 |
# File 'lib/perobs/FixedSizeBlobFile.rb', line 92 def clear @f.truncate(0) @f.flush @free_list.clear end |
#close ⇒ Object
Close the blob file. This method must be called before the program is terminated to avoid data loss.
70 71 72 73 74 75 76 77 78 79 |
# File 'lib/perobs/FixedSizeBlobFile.rb', line 70 def close @free_list.close begin @f.flush @f.flock(File::LOCK_UN) @f.close rescue IOError => e PEROBS.log.fatal "Cannot close blob file #{@file_name}: #{e.}" end end |
#delete_blob(address) ⇒ Object
Delete the blob at the given address.
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
# File 'lib/perobs/FixedSizeBlobFile.rb', line 162 def delete_blob(address) begin @f.seek(address_to_offset(address)) if (@f.read(1).unpack('C')[0] != 1) PEROBS.log.fatal "There is no blob stored at address #{address}" end @f.seek(address_to_offset(address)) @f.write([ 0 ].pack('C')) rescue IOError => e PEROBS.log.fatal "Cannot delete blob at address #{address}: " + e. end # Add the address to the free list. @free_list.push([ address ].pack('Q')) end |
#empty? ⇒ Boolean
98 99 100 101 |
# File 'lib/perobs/FixedSizeBlobFile.rb', line 98 def empty? sync @f.size == 0 end |
#free_address ⇒ Fixnum
Return the address of a free blob storage space. Addresses start at 0 and increase linearly.
106 107 108 109 110 111 112 113 114 115 |
# File 'lib/perobs/FixedSizeBlobFile.rb', line 106 def free_address if (bytes = @free_list.pop) # Return an entry from the free list. return bytes.unpack('Q')[0] else # There is currently no free entry. Return the address at the end of # the file. offset_to_address(@f.size) end end |
#open ⇒ Object
Open the blob file.
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
# File 'lib/perobs/FixedSizeBlobFile.rb', line 52 def open begin if File.exist?(@file_name) @f = File.open(@file_name, 'rb+') else @f = File.open(@file_name, 'wb+') end rescue IOError => e PEROBS.log.fatal "Cannot open blob file #{@file_name}: #{e.}" end unless @f.flock(File::LOCK_NB | File::LOCK_EX) PEROBS.log.fatal 'Database blob file is locked by another process' end @free_list.open end |
#retrieve_blob(address) ⇒ String
Retrieve a blob from the given address.
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
# File 'lib/perobs/FixedSizeBlobFile.rb', line 141 def retrieve_blob(address) begin if (offset = address_to_offset(address)) >= @f.size return nil end @f.seek(address_to_offset(address)) if (@f.read(1).unpack('C')[0] != 1) return nil end bytes = @f.read(@entry_bytes) rescue IOError => e PEROBS.log.fatal "Cannot retrieve blob at adress #{address}: " + e. end bytes end |
#store_blob(address, bytes) ⇒ Object
Store the given byte blob at the specified address. If the blob space is already in use the content will be overwritten.
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
# File 'lib/perobs/FixedSizeBlobFile.rb', line 121 def store_blob(address, bytes) if bytes.length != @entry_bytes PEROBS.log.fatal "All stack entries must be #{@entry_bytes} " + "long. This entry is #{bytes.length} bytes long." end begin @f.seek(address_to_offset(address)) # The first byte is tha flag byte. It's set to 1 for cells that hold a # blob. 0 for empty cells. @f.write([ 1 ].pack('C')) @f.write(bytes) @f.flush rescue IOError => e PEROBS.log.fatal "Cannot store blob at address #{address}: #{e.}" end end |