Class: Rubcask::Directory
- Inherits:
-
Object
- Object
- Rubcask::Directory
- Extended by:
- Forwardable
- Defined in:
- lib/rubcask/directory.rb
Class Method Summary collapse
-
.with_directory(dir, config: Config.new) {|directory| ... } ⇒ void
yields directory to the block and closes it after the block is terminated.
Instance Method Summary collapse
-
#[](key) ⇒ String?
Gets value associated with the key.
-
#[]=(key, value) ⇒ String
Set value associated with given key.
-
#clear_files ⇒ Object
Removes files that are not needed after the merge.
-
#close ⇒ Object
Closes all the files and the worker.
-
#delete(key) ⇒ Object
Remove entry associated with the key.
-
#each {|key, value| ... } ⇒ Enumerator<Array(String, String)>
If no block given.
-
#each_key {|key| ... } ⇒ Enumerator<String>
If no block given.
-
#generate_missing_hint_files! ⇒ Object
Generate hint files for data files that do not have hint files.
-
#initialize(dir, config: Config.new) ⇒ Directory
constructor
A new instance of Directory.
-
#key_count ⇒ Integer
Returns number of keys in the store.
-
#keys ⇒ Array<String>
Returns array of keys in store.
-
#merge ⇒ Object
Starts the merge operation.
-
#regenerate_hint_files! ⇒ Object
Generate hint files for all the data files.
-
#set_with_ttl(key, value, ttl) ⇒ String
Set value associated with given key with given ttl.
Constructor Details
#initialize(dir, config: Config.new) ⇒ Directory
Returns a new instance of Directory.
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
# File 'lib/rubcask/directory.rb', line 61 def initialize(dir, config: Config.new) @dir = dir @config = check_config(config) max_id = 0 files = dir_data_files @files = files.each_with_object({}) do |file, hash| next if File.executable?(file) if file.equal?(files.last) && File.size(file) < config.max_file_size hinted_file = open_write_file(file) @active = hinted_file else hinted_file = open_read_only_file(file) end id = hinted_file.id hash[id] = hinted_file max_id = id # dir_data_files returns an already sorted collection end @max_id = (config.threadsafe ? Concurrent::AtomicFixnum : Concurrency::FakeAtomicFixnum).new(max_id) @lock = config.threadsafe ? Concurrent::ReentrantReadWriteLock.new : Concurrency::FakeLock.new @worker = Worker::Factory.new_worker(@config.worker) @logger = Logger.new($stdin) @logger.level = Logger::INFO @merge_mutex = Thread::Mutex.new load_keydir! create_new_file! unless @active end |
Class Method Details
.with_directory(dir, config: Config.new) {|directory| ... } ⇒ void
This method returns an undefined value.
yields directory to the block and closes it after the block is terminated
38 39 40 41 42 43 44 45 |
# File 'lib/rubcask/directory.rb', line 38 def self.with_directory(dir, config: Config.new) directory = new(dir, config: config) begin yield directory ensure directory.close end end |
Instance Method Details
#[](key) ⇒ String?
key is always treated as byte array, encoding is ignored
Gets value associated with the key
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'lib/rubcask/directory.rb', line 123 def [](key) key = normalize_key(key) entry = nil data_file = nil @lock.with_read_lock do entry = @keydir[key] return nil unless entry if entry.expired? return nil end data_file = @files[entry.file_id] # We are using pread so there's no need to synchronize the read value = data_file.pread(entry.value_pos, entry.value_size).value return nil if Tombstone.is_tombstone?(value) return value end end |
#[]=(key, value) ⇒ String
key is always treated as byte array, encoding is ignored
Set value associated with given key.
99 100 101 102 |
# File 'lib/rubcask/directory.rb', line 99 def []=(key, value) put(key, value, NO_EXPIRE_TIMESTAMP) value # rubocop:disable Lint/Void end |
#clear_files ⇒ Object
Removes files that are not needed after the merge
246 247 248 |
# File 'lib/rubcask/directory.rb', line 246 def clear_files worker.push(Rubcask::Task::CleanDirectory.new(@dir)) end |
#close ⇒ Object
Closes all the files and the worker
181 182 183 184 185 186 187 188 189 |
# File 'lib/rubcask/directory.rb', line 181 def close @lock.with_write_lock do @files.each_value(&:close) if active.write_pos == 0 File.delete(active.path) end end worker.close end |
#delete(key) ⇒ Object
key is always treated as byte array, encoding is ignored
Remove entry associated with the key.
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
# File 'lib/rubcask/directory.rb', line 149 def delete(key) key = normalize_key(key) @lock.with_write_lock do prev_val = @keydir[key] if prev_val.nil? return false end if prev_val.expired? @keydir.delete(key) return false end do_delete(key, prev_val.file_id) true end end |
#each {|key, value| ... } ⇒ Enumerator<Array(String, String)>
This method blocks writes for the entire iteration
Keys might be in any order
Returns if no block given.
196 197 198 199 200 201 202 203 204 205 206 207 |
# File 'lib/rubcask/directory.rb', line 196 def each return to_enum(__method__) unless block_given? @lock.with_read_lock do @keydir.each do |key, entry| file = @files[entry.file_id] value = file[entry.value_pos, entry.value_size].value next if Tombstone.is_tombstone?(value) yield [key, value] end end end |
#each_key {|key| ... } ⇒ Enumerator<String>
It might include deleted keys
Keys might be in any order
This method blocks writes for the entire iteration
Returns if no block given.
214 215 216 217 218 219 220 |
# File 'lib/rubcask/directory.rb', line 214 def each_key(&block) return to_enum(__method__) unless block @lock.with_read_lock do @keydir.each_key(&block) end end |
#generate_missing_hint_files! ⇒ Object
Generate hint files for data files that do not have hint files
223 224 225 226 227 228 229 230 231 232 |
# File 'lib/rubcask/directory.rb', line 223 def generate_missing_hint_files! @lock.with_read_lock do @files.each_value do |data_file| next if data_file.has_hint_file? && !data_file.dirty? data_file.synchronize do data_file.save_hint_file end end end end |
#key_count ⇒ Integer
It might count some deleted keys
Returns number of keys in the store
253 254 255 256 257 |
# File 'lib/rubcask/directory.rb', line 253 def key_count @lock.with_read_lock do @keydir.size end end |
#keys ⇒ Array<String>
It might include deleted keys
Keys might be in any order
Returns array of keys in store
263 264 265 266 267 |
# File 'lib/rubcask/directory.rb', line 263 def keys @lock.with_read_lock do @keydir.keys end end |
#merge ⇒ Object
Starts the merge operation.
167 168 169 170 171 172 173 174 175 176 177 178 |
# File 'lib/rubcask/directory.rb', line 167 def merge unless @merge_mutex.try_lock raise MergeAlreadyInProgressError, "Merge is already in progress" end begin non_synced_merge rescue => ex logger.error("Error while merging #{ex}") ensure @merge_mutex.unlock end end |
#regenerate_hint_files! ⇒ Object
Generate hint files for all the data files
235 236 237 238 239 240 241 242 243 |
# File 'lib/rubcask/directory.rb', line 235 def regenerate_hint_files! @lock.with_read_lock do @files.each_value do |data_file| data_file.synchronize do data_file.save_hint_file end end end end |
#set_with_ttl(key, value, ttl) ⇒ String
key is always treated as byte array, encoding is ignored
Set value associated with given key with given ttl
112 113 114 115 116 |
# File 'lib/rubcask/directory.rb', line 112 def set_with_ttl(key, value, ttl) raise ArgumentError, "Negative ttl" if ttl.negative? put(key, value, Time.now.to_i + ttl) value # rubocop:disable Lint/Void end |