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



51
52
53
# File 'lib/specwrk/store/file_adapter.rb', line 51

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

.schedule_work(&blk) ⇒ Object



34
35
36
37
# File 'lib/specwrk/store/file_adapter.rb', line 34

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

.start_threads!Object



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

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
# 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")

  Thread.pass until lock_file.flock(File::LOCK_EX)

  yield
ensure
  lock_file.flock(File::LOCK_UN)
end

Instance Method Details

#[](key) ⇒ Object



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

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

  self.class.serializer.load(content)
end

#[]=(key, value) ⇒ Object



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

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



77
78
79
80
# File 'lib/specwrk/store/file_adapter.rb', line 77

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

#delete(*keys) ⇒ Object



82
83
84
85
86
# File 'lib/specwrk/store/file_adapter.rb', line 82

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

  FileUtils.rm_f(filenames)
end

#empty?Boolean

Returns:

  • (Boolean)


132
133
134
# File 'lib/specwrk/store/file_adapter.rb', line 132

def empty?
  Dir.empty? path
end

#keysObject



73
74
75
# File 'lib/specwrk/store/file_adapter.rb', line 73

def keys
  known_key_pairs.keys
end

#merge!(h2) ⇒ Object



88
89
90
# File 'lib/specwrk/store/file_adapter.rb', line 88

def merge!(h2)
  multi_write(h2)
end

#multi_read(*read_keys) ⇒ Object



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

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



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

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