identity_cache 1.0.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +76 -9
- data/.github/workflows/cla.yml +22 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +7 -3
- data/.spin/bootstrap +7 -0
- data/.spin/svc.yml +2 -0
- data/CAVEATS.md +25 -0
- data/CHANGELOG.md +56 -22
- data/Gemfile +15 -5
- data/LICENSE +1 -1
- data/README.md +27 -8
- data/Rakefile +13 -12
- data/dev.yml +5 -4
- data/gemfiles/Gemfile.latest-release +12 -5
- data/gemfiles/Gemfile.min-supported +12 -0
- data/gemfiles/Gemfile.rails-edge +9 -5
- data/identity_cache.gemspec +15 -24
- data/{railgun.yml → isogun.yml} +0 -5
- data/lib/identity_cache/belongs_to_caching.rb +1 -0
- data/lib/identity_cache/cache_fetcher.rb +241 -16
- data/lib/identity_cache/cache_hash.rb +7 -6
- data/lib/identity_cache/cache_invalidation.rb +2 -1
- data/lib/identity_cache/cache_key_generation.rb +22 -19
- data/lib/identity_cache/cache_key_loader.rb +2 -2
- data/lib/identity_cache/cached/association.rb +2 -4
- data/lib/identity_cache/cached/attribute.rb +3 -3
- data/lib/identity_cache/cached/attribute_by_multi.rb +1 -1
- data/lib/identity_cache/cached/belongs_to.rb +24 -14
- data/lib/identity_cache/cached/embedded_fetching.rb +2 -0
- data/lib/identity_cache/cached/prefetcher.rb +12 -2
- data/lib/identity_cache/cached/primary_index.rb +3 -3
- data/lib/identity_cache/cached/recursive/association.rb +55 -12
- data/lib/identity_cache/cached/recursive/has_many.rb +1 -0
- data/lib/identity_cache/cached/recursive/has_one.rb +1 -0
- data/lib/identity_cache/cached/reference/association.rb +1 -0
- data/lib/identity_cache/cached/reference/has_many.rb +3 -2
- data/lib/identity_cache/cached/reference/has_one.rb +3 -2
- data/lib/identity_cache/cached.rb +1 -0
- data/lib/identity_cache/configuration_dsl.rb +1 -0
- data/lib/identity_cache/encoder.rb +2 -1
- data/lib/identity_cache/expiry_hook.rb +2 -1
- data/lib/identity_cache/fallback_fetcher.rb +6 -1
- data/lib/identity_cache/mem_cache_store_cas.rb +63 -0
- data/lib/identity_cache/memoized_cache_proxy.rb +33 -23
- data/lib/identity_cache/parent_model_expiration.rb +6 -3
- data/lib/identity_cache/query_api.rb +29 -66
- data/lib/identity_cache/railtie.rb +1 -0
- data/lib/identity_cache/should_use_cache.rb +1 -0
- data/lib/identity_cache/version.rb +2 -1
- data/lib/identity_cache/with_primary_index.rb +37 -10
- data/lib/identity_cache/without_primary_index.rb +7 -3
- data/lib/identity_cache.rb +66 -26
- data/performance/cache_runner.rb +12 -51
- data/performance/cpu.rb +7 -6
- data/performance/externals.rb +6 -5
- data/performance/profile.rb +7 -6
- metadata +32 -112
- data/.github/probots.yml +0 -2
- data/.travis.yml +0 -45
- data/gemfiles/Gemfile.rails52 +0 -6
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module IdentityCache
|
3
4
|
module WithPrimaryIndex
|
4
5
|
extend ActiveSupport::Concern
|
@@ -57,7 +58,7 @@ module IdentityCache
|
|
57
58
|
cache_attribute_by_alias(attribute_proc, alias_name: :id, by: fields, unique: unique)
|
58
59
|
|
59
60
|
field_list = fields.join("_and_")
|
60
|
-
arg_list = (0...fields.size).collect { |i| "arg#{i}" }.join(
|
61
|
+
arg_list = (0...fields.size).collect { |i| "arg#{i}" }.join(",")
|
61
62
|
|
62
63
|
if unique
|
63
64
|
instance_eval(<<-CODE, __FILE__, __LINE__ + 1)
|
@@ -97,21 +98,47 @@ module IdentityCache
|
|
97
98
|
!!fetch_by_id(id)
|
98
99
|
end
|
99
100
|
|
100
|
-
#
|
101
|
-
#
|
102
|
-
|
101
|
+
# Fetch the record by its primary key from the cache or read from
|
102
|
+
# the database and fill the cache on a cache miss. This behaves like
|
103
|
+
# `where(id: id).readonly.first` being called on the model.
|
104
|
+
#
|
105
|
+
# @param id Primary key value for the record to fetch.
|
106
|
+
# @param includes [Hash|Array|Symbol] Cached associations to prefetch from
|
107
|
+
# the cache on the returned record
|
108
|
+
# @param fill_lock_duration [Float] If provided, take a fill lock around cache fills
|
109
|
+
# and wait for this duration for cache to be filled when reading a lock provided
|
110
|
+
# by another client. Defaults to not setting the fill lock and trying to fill the
|
111
|
+
# cache from the database regardless of the presence of another client's fill lock.
|
112
|
+
# Set this to just above the typical amount of time it takes to do a cache fill.
|
113
|
+
# @param lock_wait_tries [Integer] Only applicable if fill_lock_duration is provided,
|
114
|
+
# in which case it specifies the number of times to do a lock wait. After the first
|
115
|
+
# lock wait it will try to take the lock, so will only do following lock waits due
|
116
|
+
# to another client taking the lock first. If another lock wait would be needed after
|
117
|
+
# reaching the limit, then a `LockWaitTimeout` exception is raised. Default is 2. Use
|
118
|
+
# this to control the maximum total lock wait duration
|
119
|
+
# (`lock_wait_tries * fill_lock_duration`).
|
120
|
+
# @raise [LockWaitTimeout] Timeout after waiting `lock_wait_tries * fill_lock_duration`
|
121
|
+
# seconds for `lock_wait_tries` other clients to fill the cache.
|
122
|
+
# @return [self|nil] An instance of this model for the record with the specified id or
|
123
|
+
# `nil` if no record with this `id` exists in the database
|
124
|
+
def fetch_by_id(id, includes: nil, **cache_fetcher_options)
|
103
125
|
ensure_base_model
|
104
126
|
raise_if_scoped
|
105
|
-
record = cached_primary_index.fetch(id)
|
127
|
+
record = cached_primary_index.fetch(id, cache_fetcher_options)
|
106
128
|
prefetch_associations(includes, [record]) if record && includes
|
107
129
|
record
|
108
130
|
end
|
109
131
|
|
110
|
-
#
|
111
|
-
#
|
112
|
-
#
|
113
|
-
|
114
|
-
|
132
|
+
# Fetch the record by its primary key from the cache or read from
|
133
|
+
# the database and fill the cache on a cache miss. This behaves like
|
134
|
+
# `readonly.find(id)` being called on the model.
|
135
|
+
#
|
136
|
+
# @param (see #fetch_by_id)
|
137
|
+
# @raise (see #fetch_by_id)
|
138
|
+
# @raise [ActiveRecord::RecordNotFound] if the record isn't found
|
139
|
+
# @return [self] An instance of this model for the record with the specified id
|
140
|
+
def fetch(id, **options)
|
141
|
+
fetch_by_id(id, **options) || raise(
|
115
142
|
IdentityCache::RecordNotFound, "Couldn't find #{name} with ID=#{id}"
|
116
143
|
)
|
117
144
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module IdentityCache
|
3
4
|
module WithoutPrimaryIndex
|
4
5
|
extend ActiveSupport::Concern
|
@@ -12,9 +13,12 @@ module IdentityCache
|
|
12
13
|
include IdentityCache::ShouldUseCache
|
13
14
|
include ParentModelExpiration
|
14
15
|
|
15
|
-
|
16
|
-
|
17
|
-
|
16
|
+
class << self
|
17
|
+
def append_features(base) # :nodoc:
|
18
|
+
raise AlreadyIncludedError if base.include?(WithoutPrimaryIndex)
|
19
|
+
|
20
|
+
super
|
21
|
+
end
|
18
22
|
end
|
19
23
|
|
20
24
|
included do
|
data/lib/identity_cache.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
2
|
+
|
3
|
+
require "active_record"
|
4
|
+
require "active_support/core_ext/module/attribute_accessors"
|
5
|
+
require "ar_transaction_changes"
|
5
6
|
|
6
7
|
require "identity_cache/version"
|
7
8
|
require "identity_cache/record_not_found"
|
@@ -27,23 +28,25 @@ require "identity_cache/cached/reference/association"
|
|
27
28
|
require "identity_cache/cached/reference/has_one"
|
28
29
|
require "identity_cache/cached/reference/has_many"
|
29
30
|
require "identity_cache/expiry_hook"
|
30
|
-
require
|
31
|
-
require
|
32
|
-
require
|
33
|
-
require
|
34
|
-
require
|
35
|
-
require
|
36
|
-
require
|
31
|
+
require "identity_cache/memoized_cache_proxy"
|
32
|
+
require "identity_cache/belongs_to_caching"
|
33
|
+
require "identity_cache/cache_key_generation"
|
34
|
+
require "identity_cache/configuration_dsl"
|
35
|
+
require "identity_cache/should_use_cache"
|
36
|
+
require "identity_cache/parent_model_expiration"
|
37
|
+
require "identity_cache/query_api"
|
37
38
|
require "identity_cache/cache_hash"
|
38
39
|
require "identity_cache/cache_invalidation"
|
39
40
|
require "identity_cache/cache_fetcher"
|
40
41
|
require "identity_cache/fallback_fetcher"
|
41
|
-
require
|
42
|
-
require
|
42
|
+
require "identity_cache/without_primary_index"
|
43
|
+
require "identity_cache/with_primary_index"
|
43
44
|
|
44
45
|
module IdentityCache
|
45
46
|
extend ActiveSupport::Concern
|
46
47
|
|
48
|
+
autoload :MemCacheStoreCAS, "identity_cache/mem_cache_store_cas"
|
49
|
+
|
47
50
|
include WithPrimaryIndex
|
48
51
|
|
49
52
|
CACHED_NIL = :idc_cached_nil
|
@@ -52,29 +55,37 @@ module IdentityCache
|
|
52
55
|
DELETED_TTL = 1000
|
53
56
|
|
54
57
|
class AlreadyIncludedError < StandardError; end
|
58
|
+
|
55
59
|
class AssociationError < StandardError; end
|
60
|
+
|
56
61
|
class InverseAssociationError < StandardError; end
|
62
|
+
|
57
63
|
class UnsupportedScopeError < StandardError; end
|
64
|
+
|
58
65
|
class UnsupportedAssociationError < StandardError; end
|
66
|
+
|
59
67
|
class DerivedModelError < StandardError; end
|
60
68
|
|
69
|
+
class LockWaitTimeout < StandardError; end
|
70
|
+
|
61
71
|
mattr_accessor :cache_namespace
|
62
72
|
self.cache_namespace = "IDC:#{CACHE_VERSION}:"
|
63
73
|
|
64
74
|
# Fetched records are not read-only and this could sometimes prevent IDC from
|
65
75
|
# reflecting what's truly in the database when fetch_read_only_records is false.
|
66
76
|
# When set to true, it will only return read-only records when cache is used.
|
67
|
-
|
68
|
-
self.fetch_read_only_records = true
|
77
|
+
@fetch_read_only_records = true
|
69
78
|
|
70
79
|
class << self
|
71
80
|
include IdentityCache::CacheHash
|
72
81
|
|
82
|
+
attr_writer :fetch_read_only_records
|
73
83
|
attr_accessor :readonly
|
74
84
|
attr_writer :logger
|
75
85
|
|
76
|
-
def append_features(base)
|
86
|
+
def append_features(base) # :nodoc:
|
77
87
|
raise AlreadyIncludedError if base.include?(IdentityCache)
|
88
|
+
|
78
89
|
super
|
79
90
|
end
|
80
91
|
|
@@ -105,8 +116,27 @@ module IdentityCache
|
|
105
116
|
end
|
106
117
|
|
107
118
|
def should_use_cache? # :nodoc:
|
108
|
-
|
109
|
-
|
119
|
+
ActiveRecord::Base.connection_handler.connection_pool_list.none? do |pool|
|
120
|
+
pool.active_connection? &&
|
121
|
+
# Rails wraps each of your tests in a transaction, so that any changes
|
122
|
+
# made to the database during the test can be rolled back afterwards.
|
123
|
+
# These transactions are flagged as "unjoinable", which tries to make
|
124
|
+
# your application behave as if they weren't there. In particular:
|
125
|
+
#
|
126
|
+
# - Opening another transaction during the test creates a savepoint,
|
127
|
+
# which can be rolled back independently of the main transaction.
|
128
|
+
# - When those nested transactions complete, any `after_commit`
|
129
|
+
# callbacks for records modified during the transaction will run,
|
130
|
+
# even though the changes haven't actually been committed yet.
|
131
|
+
#
|
132
|
+
# By ignoring unjoinable transactions, IdentityCache's behaviour
|
133
|
+
# during your test suite will more closely match production.
|
134
|
+
#
|
135
|
+
# When there are no open transactions, `current_transaction` returns a
|
136
|
+
# special `NullTransaction` object that is unjoinable, meaning we will
|
137
|
+
# use the cache.
|
138
|
+
pool.connection.current_transaction.joinable?
|
139
|
+
end
|
110
140
|
end
|
111
141
|
|
112
142
|
# Cache retrieval and miss resolver primitive; given a key it will try to
|
@@ -115,10 +145,13 @@ module IdentityCache
|
|
115
145
|
#
|
116
146
|
# == Parameters
|
117
147
|
# +key+ A cache key string
|
148
|
+
# +cache_fetcher_options+ A hash of options to pass to the cache backend
|
118
149
|
#
|
119
|
-
def fetch(key)
|
150
|
+
def fetch(key, cache_fetcher_options = {})
|
120
151
|
if should_use_cache?
|
121
|
-
unmap_cached_nil_for(cache.fetch(key)
|
152
|
+
unmap_cached_nil_for(cache.fetch(key, cache_fetcher_options) do
|
153
|
+
map_cached_nil_for(yield)
|
154
|
+
end)
|
122
155
|
else
|
123
156
|
yield
|
124
157
|
end
|
@@ -144,7 +177,7 @@ module IdentityCache
|
|
144
177
|
result = if should_use_cache?
|
145
178
|
fetch_in_batches(keys.uniq) do |missed_keys|
|
146
179
|
results = yield missed_keys
|
147
|
-
results.map { |e| map_cached_nil_for
|
180
|
+
results.map { |e| map_cached_nil_for(e) }
|
148
181
|
end
|
149
182
|
else
|
150
183
|
results = yield keys
|
@@ -159,11 +192,18 @@ module IdentityCache
|
|
159
192
|
end
|
160
193
|
|
161
194
|
def with_fetch_read_only_records(value = true)
|
162
|
-
old_value =
|
163
|
-
|
195
|
+
old_value = Thread.current[:identity_cache_fetch_read_only_records]
|
196
|
+
Thread.current[:identity_cache_fetch_read_only_records] = value
|
164
197
|
yield
|
165
198
|
ensure
|
166
|
-
|
199
|
+
Thread.current[:identity_cache_fetch_read_only_records] = old_value
|
200
|
+
end
|
201
|
+
|
202
|
+
def fetch_read_only_records
|
203
|
+
v = Thread.current[:identity_cache_fetch_read_only_records]
|
204
|
+
return v unless v.nil?
|
205
|
+
|
206
|
+
@fetch_read_only_records
|
167
207
|
end
|
168
208
|
|
169
209
|
def eager_load!
|
@@ -172,12 +212,12 @@ module IdentityCache
|
|
172
212
|
|
173
213
|
private
|
174
214
|
|
175
|
-
def fetch_in_batches(keys)
|
215
|
+
def fetch_in_batches(keys, &block)
|
176
216
|
keys.each_slice(BATCH_SIZE).each_with_object({}) do |slice, result|
|
177
|
-
result.merge!(cache.fetch_multi(*slice
|
217
|
+
result.merge!(cache.fetch_multi(*slice, &block))
|
178
218
|
end
|
179
219
|
end
|
180
220
|
end
|
181
221
|
end
|
182
222
|
|
183
|
-
require
|
223
|
+
require "identity_cache/railtie" if defined?(Rails)
|
data/performance/cache_runner.rb
CHANGED
@@ -1,15 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
$LOAD_PATH.unshift(File.expand_path("../../lib", __FILE__))
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
4
|
+
require "active_record"
|
5
|
+
require "active_support/core_ext"
|
6
|
+
require "active_support/cache"
|
7
|
+
require "identity_cache"
|
8
|
+
require "memcached_store"
|
9
|
+
require "active_support/cache/memcached_store"
|
9
10
|
|
10
|
-
require File.dirname(__FILE__) +
|
11
|
-
require File.dirname(__FILE__) +
|
12
|
-
require File.dirname(__FILE__) +
|
11
|
+
require File.dirname(__FILE__) + "/../test/helpers/active_record_objects"
|
12
|
+
require File.dirname(__FILE__) + "/../test/helpers/database_connection"
|
13
|
+
require File.dirname(__FILE__) + "/../test/helpers/cache_connection"
|
13
14
|
|
14
15
|
IdentityCache.logger = Logger.new(nil)
|
15
16
|
CacheConnection.setup
|
@@ -31,6 +32,7 @@ def create_database(count)
|
|
31
32
|
helper.setup_models
|
32
33
|
|
33
34
|
return if database_ready(count)
|
35
|
+
|
34
36
|
puts "Database not ready for performance testing, generating records"
|
35
37
|
|
36
38
|
DatabaseConnection.drop_tables
|
@@ -38,6 +40,7 @@ def create_database(count)
|
|
38
40
|
existing = Item.all
|
39
41
|
(1..count).to_a.each do |i|
|
40
42
|
next if existing.any? { |e| e.id == i }
|
43
|
+
|
41
44
|
a = Item.new
|
42
45
|
a.id = i
|
43
46
|
a.associated = AssociatedRecord.new(name: "Associated for #{i}")
|
@@ -107,28 +110,6 @@ module DeletedRunner
|
|
107
110
|
end
|
108
111
|
end
|
109
112
|
|
110
|
-
module ConflictRunner
|
111
|
-
def prepare
|
112
|
-
super
|
113
|
-
records = (1..@count).map { |id| ::Item.find(id) }
|
114
|
-
orig_resolve_cache_miss = ::Item.method(:resolve_cache_miss)
|
115
|
-
|
116
|
-
::Item.define_singleton_method(:resolve_cache_miss) do |id|
|
117
|
-
records[id - 1].expire_cache
|
118
|
-
orig_resolve_cache_miss.call(id)
|
119
|
-
end
|
120
|
-
IdentityCache.cache.clear
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
module DeletedConflictRunner
|
125
|
-
include ConflictRunner
|
126
|
-
def prepare
|
127
|
-
super
|
128
|
-
(1..@count).each { |i| ::Item.find(i).expire_cache }
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
113
|
class EmbedRunner < CacheRunner
|
133
114
|
def setup_models
|
134
115
|
super
|
@@ -161,16 +142,6 @@ class FetchEmbedDeletedRunner < EmbedRunner
|
|
161
142
|
end
|
162
143
|
CACHE_RUNNERS << FetchEmbedDeletedRunner
|
163
144
|
|
164
|
-
class FetchEmbedConflictRunner < EmbedRunner
|
165
|
-
include ConflictRunner
|
166
|
-
end
|
167
|
-
CACHE_RUNNERS << FetchEmbedConflictRunner
|
168
|
-
|
169
|
-
class FetchEmbedDeletedConflictRunner < EmbedRunner
|
170
|
-
include DeletedConflictRunner
|
171
|
-
end
|
172
|
-
CACHE_RUNNERS << FetchEmbedDeletedConflictRunner
|
173
|
-
|
174
145
|
class NormalizedRunner < CacheRunner
|
175
146
|
def setup_models
|
176
147
|
super
|
@@ -204,13 +175,3 @@ class FetchNormalizedDeletedRunner < NormalizedRunner
|
|
204
175
|
include DeletedRunner
|
205
176
|
end
|
206
177
|
CACHE_RUNNERS << FetchNormalizedDeletedRunner
|
207
|
-
|
208
|
-
class FetchNormalizedConflictRunner < EmbedRunner
|
209
|
-
include ConflictRunner
|
210
|
-
end
|
211
|
-
CACHE_RUNNERS << FetchNormalizedConflictRunner
|
212
|
-
|
213
|
-
class FetchNormalizedDeletedConflictRunner < EmbedRunner
|
214
|
-
include DeletedConflictRunner
|
215
|
-
end
|
216
|
-
CACHE_RUNNERS << FetchNormalizedDeletedConflictRunner
|
data/performance/cpu.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
require 'rubygems'
|
3
|
-
require 'benchmark'
|
4
2
|
|
5
|
-
|
3
|
+
require "rubygems"
|
4
|
+
require "benchmark"
|
5
|
+
|
6
|
+
require_relative "cache_runner"
|
6
7
|
|
7
8
|
RUNS = 400
|
8
9
|
|
@@ -23,7 +24,7 @@ end
|
|
23
24
|
def benchmark(runners, label_width = 0)
|
24
25
|
IdentityCache.cache.clear
|
25
26
|
runners.each do |runner|
|
26
|
-
print
|
27
|
+
print("#{runner.name}: ".ljust(label_width))
|
27
28
|
puts run(runner.new(RUNS))
|
28
29
|
end
|
29
30
|
end
|
@@ -32,9 +33,9 @@ def bmbm(runners)
|
|
32
33
|
label_width = runners.map { |r| r.name.size }.max + 2
|
33
34
|
width = label_width + Benchmark::CAPTION.size
|
34
35
|
|
35
|
-
puts
|
36
|
+
puts "Rehearsal: ".ljust(width, "-")
|
36
37
|
benchmark(runners, label_width)
|
37
|
-
puts
|
38
|
+
puts "-" * width
|
38
39
|
|
39
40
|
benchmark(runners, label_width)
|
40
41
|
end
|
data/performance/externals.rb
CHANGED
@@ -1,15 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
require 'rubygems'
|
3
|
-
require 'benchmark'
|
4
|
-
require 'ruby-prof'
|
5
2
|
|
6
|
-
|
3
|
+
require "rubygems"
|
4
|
+
require "benchmark"
|
5
|
+
require "ruby-prof"
|
6
|
+
|
7
|
+
require_relative "cache_runner"
|
7
8
|
|
8
9
|
RUNS = 1000
|
9
10
|
RubyProf.measure_mode = RubyProf::CPU_TIME
|
10
11
|
|
11
12
|
EXTERNALS = { "Memcache" => ["MemCache#set", "MemCache#get"],
|
12
|
-
"Database" => ["Mysql2::Client#query"] }
|
13
|
+
"Database" => ["Mysql2::Client#query"], }
|
13
14
|
|
14
15
|
def run(obj)
|
15
16
|
obj.prepare
|
data/performance/profile.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
require 'rubygems'
|
3
|
-
require 'benchmark'
|
4
|
-
require 'stackprof'
|
5
2
|
|
6
|
-
|
3
|
+
require "rubygems"
|
4
|
+
require "benchmark"
|
5
|
+
require "stackprof"
|
6
|
+
|
7
|
+
require_relative "cache_runner"
|
7
8
|
|
8
9
|
RUNS = 1000
|
9
10
|
|
@@ -22,9 +23,9 @@ end
|
|
22
23
|
|
23
24
|
create_database(RUNS)
|
24
25
|
|
25
|
-
if (runner_name = ENV[
|
26
|
+
if (runner_name = ENV["RUNNER"])
|
26
27
|
if (runner = CACHE_RUNNERS.find { |r| r.name == runner_name })
|
27
|
-
run(runner.new(RUNS), filename: ENV[
|
28
|
+
run(runner.new(RUNS), filename: ENV["FILENAME"])
|
28
29
|
else
|
29
30
|
puts "Couldn't find cache runner #{runner_name.inspect}"
|
30
31
|
exit(1)
|