class Bootsnap::LoadPathCache::Store
Constants
- CURRENT_VERSION
- NestedTransactionError
- SetOutsideTransactionNotAllowed
- VERSION_KEY
Public Class Methods
Source
# File lib/bootsnap/load_path_cache/store.rb, line 16 def initialize(store_path, readonly: false) @store_path = store_path @txn_mutex = Mutex.new @dirty = false @readonly = readonly load_data end
Public Instance Methods
Source
# File lib/bootsnap/load_path_cache/store.rb, line 28 def fetch(key) raise(SetOutsideTransactionNotAllowed) unless @txn_mutex.owned? v = get(key) unless v v = yield mark_for_mutation! @data[key] = v end v end
Source
# File lib/bootsnap/load_path_cache/store.rb, line 40 def set(key, value) raise(SetOutsideTransactionNotAllowed) unless @txn_mutex.owned? if value != @data[key] mark_for_mutation! @data[key] = value end end
Source
# File lib/bootsnap/load_path_cache/store.rb, line 49 def transaction raise(NestedTransactionError) if @txn_mutex.owned? @txn_mutex.synchronize do yield ensure commit_transaction end end
Private Instance Methods
Source
# File lib/bootsnap/load_path_cache/store.rb, line 66 def commit_transaction if @dirty && !@readonly dump_data @dirty = false end end
Source
# File lib/bootsnap/load_path_cache/store.rb, line 112 def default_data {VERSION_KEY => CURRENT_VERSION} end
Source
# File lib/bootsnap/load_path_cache/store.rb, line 95 def dump_data # Change contents atomically so other processes can't get invalid # caches if they read at an inopportune time. tmp = "#{@store_path}.#{Process.pid}.#{(rand * 100_000).to_i}.tmp" mkdir_p(File.dirname(tmp)) exclusive_write = File::Constants::CREAT | File::Constants::EXCL | File::Constants::WRONLY # `encoding:` looks redundant wrt `binwrite`, but necessary on windows # because binary is part of mode. File.open(tmp, mode: exclusive_write, encoding: Encoding::BINARY) do |io| MessagePack.dump(@data, io) end File.rename(tmp, @store_path) rescue Errno::EEXIST retry rescue SystemCallError end
Source
# File lib/bootsnap/load_path_cache/store.rb, line 73 def load_data @data = begin data = File.open(@store_path, encoding: Encoding::BINARY) do |io| MessagePack.load(io, freeze: true) end if data.is_a?(Hash) && data[VERSION_KEY] == CURRENT_VERSION data else default_data end # handle malformed data due to upgrade incompatibility rescue Errno::ENOENT, MessagePack::MalformedFormatError, MessagePack::UnknownExtTypeError, EOFError default_data rescue ArgumentError => error if error.message =~ /negative array size/ default_data else raise end end end
Source
# File lib/bootsnap/load_path_cache/store.rb, line 61 def mark_for_mutation! @dirty = true @data = @data.dup if @data.frozen? end
Source
# File lib/bootsnap/load_path_cache/store.rb, line 116 def mkdir_p(path) stack = [] until File.directory?(path) stack.push path path = File.dirname(path) end stack.reverse_each do |dir| Dir.mkdir(dir) rescue SystemCallError raise unless File.directory?(dir) end end