Class: Specwrk::Store::FileAdapter

Inherits:
BaseAdapter show all
Defined in:
lib/specwrk/store/file_adapter.rb

Constant Summary collapse

READ_ATTEMPTS =
3
READ_RETRY_DELAY =
0.01

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from BaseAdapter

#initialize, reset_serializer!, serializer

Constructor Details

This class inherits a constructor from Specwrk::Store::BaseAdapter

Class Method Details

.extObject



53
54
55
# File 'lib/specwrk/store/file_adapter.rb', line 53

def ext
  ".wrk.#{serializer.adapter_name}"
end

.schedule_work(&blk) ⇒ Object



36
37
38
39
# File 'lib/specwrk/store/file_adapter.rb', line 36

def schedule_work(&blk)
  start_threads!
  @work_queue.push blk
end

.start_threads!Object



41
42
43
44
45
46
47
48
49
50
51
# File 'lib/specwrk/store/file_adapter.rb', line 41

def start_threads!
  return if @threads.length.positive?

  Array.new(ENV.fetch("SPECWRK_THREAD_COUNT", "4").to_i) do
    @threads << Thread.new do
      loop do
        @work_queue.pop.call
      end
    end
  end
end

.with_lock(uri, key) ⇒ Object



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/specwrk/store/file_adapter.rb', line 20

def with_lock(uri, key)
  lock_file_path = File.join(uri.path, "#{key}.lock").tap do |path|
    FileUtils.mkdir_p(uri.path)
  end

  lock_file = File.open(lock_file_path, "a")

  locked = lock_file.flock(File::LOCK_EX | File::LOCK_NB)
  raise LockUnavailableError unless locked

  yield
ensure
  lock_file&.flock(File::LOCK_UN) if locked
  lock_file&.close
end

Instance Method Details

#[](key) ⇒ Object



58
59
60
61
62
63
# File 'lib/specwrk/store/file_adapter.rb', line 58

def [](key)
  content = read(key.to_s)
  return unless content

  self.class.serializer.load(content)
end

#[]=(key, value) ⇒ Object



65
66
67
68
69
70
71
72
73
# File 'lib/specwrk/store/file_adapter.rb', line 65

def []=(key, value)
  key_string = key.to_s
  if value.nil?
    delete(key_string)
  else
    filename = filename_for_key(key_string)
    write(filename, self.class.serializer.dump(value))
  end
end

#clearObject



79
80
81
82
# File 'lib/specwrk/store/file_adapter.rb', line 79

def clear
  FileUtils.rm_rf(path)
  FileUtils.mkdir_p(path)
end

#delete(*keys) ⇒ Object



84
85
86
87
88
# File 'lib/specwrk/store/file_adapter.rb', line 84

def delete(*keys)
  filenames = keys.map { |key| filename_for_key key }.compact

  FileUtils.rm_f(filenames)
end

#empty?Boolean

Returns:

  • (Boolean)


134
135
136
# File 'lib/specwrk/store/file_adapter.rb', line 134

def empty?
  Dir.empty? path
end

#keysObject



75
76
77
# File 'lib/specwrk/store/file_adapter.rb', line 75

def keys
  known_key_pairs.keys
end

#merge!(h2) ⇒ Object



90
91
92
# File 'lib/specwrk/store/file_adapter.rb', line 90

def merge!(h2)
  multi_write(h2)
end

#multi_read(*read_keys) ⇒ Object



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/specwrk/store/file_adapter.rb', line 94

def multi_read(*read_keys)
  result_queue = Queue.new

  read_keys.each do |key|
    self.class.schedule_work do
      result_queue.push([:ok, key.to_s, read(key)])
    rescue => e
      result_queue.push([:error, key.to_s, e])
    end
  end

  raw_results = read_keys.length.times.map { result_queue.pop }
  error = raw_results.find { |status, _key, _result| status == :error }
  raise error.last if error

  results = {}
  raw_results.each do |_status, key, content|
    next if content.nil?

    results[key] = self.class.serializer.load(content)
  end

  read_keys.map { |key| [key.to_s, results[key.to_s]] if results.key?(key.to_s) }.compact.to_h # respect order requested in the returned hash
end

#multi_write(hash) ⇒ Object



119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/specwrk/store/file_adapter.rb', line 119

def multi_write(hash)
  result_queue = Queue.new

  hash_with_filenames = hash.map { |key, value| [key.to_s, [filename_for_key(key.to_s), value]] }.to_h
  hash_with_filenames.each do |key, (filename, value)|
    content = self.class.serializer.dump(value)

    self.class.schedule_work do
      result_queue << write(filename, content)
    end
  end

  Thread.pass until result_queue.length == hash.length
end