atomic_cache 0.1.0.rc1
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 +7 -0
- data/.gitignore +51 -0
- data/.ruby_version +1 -0
- data/.travis.yml +26 -0
- data/CODE_OF_CONDUCT.md +46 -0
- data/Gemfile +6 -0
- data/LICENSE +201 -0
- data/README.md +49 -0
- data/Rakefile +6 -0
- data/atomic_cache.gemspec +36 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/docs/ARCH.md +34 -0
- data/docs/INTERFACES.md +45 -0
- data/docs/MODEL_SETUP.md +31 -0
- data/docs/PROJECT_SETUP.md +68 -0
- data/docs/USAGE.md +106 -0
- data/docs/img/quick_retry_graph.png +0 -0
- data/lib/atomic_cache.rb +11 -0
- data/lib/atomic_cache/atomic_cache_client.rb +197 -0
- data/lib/atomic_cache/concerns/global_lmt_cache_concern.rb +111 -0
- data/lib/atomic_cache/default_config.rb +62 -0
- data/lib/atomic_cache/key/keyspace.rb +98 -0
- data/lib/atomic_cache/key/last_mod_time_key_manager.rb +95 -0
- data/lib/atomic_cache/storage/dalli.rb +46 -0
- data/lib/atomic_cache/storage/instance_memory.rb +37 -0
- data/lib/atomic_cache/storage/memory.rb +67 -0
- data/lib/atomic_cache/storage/shared_memory.rb +40 -0
- data/lib/atomic_cache/storage/store.rb +31 -0
- data/lib/atomic_cache/version.rb +5 -0
- metadata +185 -0
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'store'
|
4
|
+
|
5
|
+
module AtomicCache
|
6
|
+
module Storage
|
7
|
+
|
8
|
+
# An abstract storage adapter which keeps all values in memory
|
9
|
+
class Memory < Store
|
10
|
+
|
11
|
+
# @abstract implement returning a Hash of the in-memory representation
|
12
|
+
def store; raise NotImplementedError end
|
13
|
+
|
14
|
+
# @abstract implement performing an operation on the store
|
15
|
+
def store_op(key, user_options=nil); raise NotImplementedError end
|
16
|
+
|
17
|
+
def add(raw_key, new_value, ttl, user_options=nil)
|
18
|
+
store_op(raw_key, user_options) do |key, options|
|
19
|
+
return false if store.has_key?(key)
|
20
|
+
write(key, new_value, ttl)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def read(raw_key, user_options=nil)
|
25
|
+
store_op(raw_key, user_options) do |key, options|
|
26
|
+
entry = store[key]
|
27
|
+
return nil unless entry.present?
|
28
|
+
|
29
|
+
return entry[:value] if entry[:ttl].nil? or entry[:ttl] == false
|
30
|
+
|
31
|
+
life = Time.now - entry[:written_at]
|
32
|
+
if (life >= entry[:ttl])
|
33
|
+
store.delete(key)
|
34
|
+
nil
|
35
|
+
else
|
36
|
+
entry[:value]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def set(raw_key, new_value, user_options=nil)
|
42
|
+
store_op(raw_key, user_options) do |key, options|
|
43
|
+
write(key, new_value, options[:expires_in])
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def delete(raw_key)
|
48
|
+
store_op(raw_key) do |key, options|
|
49
|
+
store.delete(key)
|
50
|
+
true
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def write(key, value, ttl=nil)
|
55
|
+
stored_value = value.to_s
|
56
|
+
stored_value = nil if value.nil?
|
57
|
+
|
58
|
+
store[key] = {
|
59
|
+
value: stored_value,
|
60
|
+
ttl: ttl || false,
|
61
|
+
written_at: Time.now
|
62
|
+
}
|
63
|
+
true
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'memory'
|
4
|
+
|
5
|
+
module AtomicCache
|
6
|
+
module Storage
|
7
|
+
|
8
|
+
# A storage adapter which keeps all values in memory, global to all threads
|
9
|
+
class SharedMemory < Memory
|
10
|
+
STORE = {}
|
11
|
+
SEMAPHORE = Mutex.new
|
12
|
+
|
13
|
+
def self.reset
|
14
|
+
STORE.clear
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.store
|
18
|
+
STORE
|
19
|
+
end
|
20
|
+
|
21
|
+
def reset
|
22
|
+
self.class.reset
|
23
|
+
end
|
24
|
+
|
25
|
+
def store
|
26
|
+
STORE
|
27
|
+
end
|
28
|
+
|
29
|
+
def store_op(key, user_options=nil)
|
30
|
+
normalized_key = key.to_sym
|
31
|
+
user_options ||= {}
|
32
|
+
|
33
|
+
SEMAPHORE.synchronize do
|
34
|
+
yield(normalized_key, user_options)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'memory'
|
4
|
+
|
5
|
+
module AtomicCache
|
6
|
+
module Storage
|
7
|
+
|
8
|
+
class Store
|
9
|
+
|
10
|
+
# @abstract (String, Object, Integer, Hash) -> Boolean
|
11
|
+
# ttl is in millis
|
12
|
+
# operation must be atomic
|
13
|
+
# returns true when the key doesn't exist and was written successfully
|
14
|
+
# returns false in all other cases
|
15
|
+
def add(key, new_value, ttl, user_options); raise NotImplementedError end
|
16
|
+
|
17
|
+
# @abstract (String, Hash) -> String
|
18
|
+
# return the `value` at `key`
|
19
|
+
def read(key, user_options); raise NotImplementedError end
|
20
|
+
|
21
|
+
# @abstract (String, Object) -> Boolean
|
22
|
+
# returns true if it succeeds; false otherwise
|
23
|
+
def set(key, new_value, user_options); raise NotImplementedError end
|
24
|
+
|
25
|
+
# @abstract (String) -> Boolean
|
26
|
+
# returns true if it succeeds; false otherwise
|
27
|
+
def delete(key, user_options); raise NotImplementedError end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
metadata
ADDED
@@ -0,0 +1,185 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: atomic_cache
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0.rc1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ibotta Developers
|
8
|
+
- Titus Stone
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2018-02-16 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: bundler
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - "~>"
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '1.14'
|
21
|
+
type: :development
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - "~>"
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '1.14'
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: gems
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: 1.0.0
|
35
|
+
type: :development
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: 1.0.0
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: rake
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - "~>"
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '10.0'
|
49
|
+
type: :development
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - "~>"
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '10.0'
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: rspec
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - "~>"
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '3.0'
|
63
|
+
type: :development
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - "~>"
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '3.0'
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: simplecov
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - "~>"
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0.15'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - "~>"
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0.15'
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: timecop
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - "~>"
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: 0.8.1
|
91
|
+
type: :development
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - "~>"
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: 0.8.1
|
98
|
+
- !ruby/object:Gem::Dependency
|
99
|
+
name: activesupport
|
100
|
+
requirement: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '4.2'
|
105
|
+
type: :runtime
|
106
|
+
prerelease: false
|
107
|
+
version_requirements: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - ">="
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '4.2'
|
112
|
+
- !ruby/object:Gem::Dependency
|
113
|
+
name: murmurhash3
|
114
|
+
requirement: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - "~>"
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0.1'
|
119
|
+
type: :runtime
|
120
|
+
prerelease: false
|
121
|
+
version_requirements: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - "~>"
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0.1'
|
126
|
+
description: desc
|
127
|
+
email: osscompliance@ibotta.com
|
128
|
+
executables: []
|
129
|
+
extensions: []
|
130
|
+
extra_rdoc_files: []
|
131
|
+
files:
|
132
|
+
- ".gitignore"
|
133
|
+
- ".ruby_version"
|
134
|
+
- ".travis.yml"
|
135
|
+
- CODE_OF_CONDUCT.md
|
136
|
+
- Gemfile
|
137
|
+
- LICENSE
|
138
|
+
- README.md
|
139
|
+
- Rakefile
|
140
|
+
- atomic_cache.gemspec
|
141
|
+
- bin/console
|
142
|
+
- bin/setup
|
143
|
+
- docs/ARCH.md
|
144
|
+
- docs/INTERFACES.md
|
145
|
+
- docs/MODEL_SETUP.md
|
146
|
+
- docs/PROJECT_SETUP.md
|
147
|
+
- docs/USAGE.md
|
148
|
+
- docs/img/quick_retry_graph.png
|
149
|
+
- lib/atomic_cache.rb
|
150
|
+
- lib/atomic_cache/atomic_cache_client.rb
|
151
|
+
- lib/atomic_cache/concerns/global_lmt_cache_concern.rb
|
152
|
+
- lib/atomic_cache/default_config.rb
|
153
|
+
- lib/atomic_cache/key/keyspace.rb
|
154
|
+
- lib/atomic_cache/key/last_mod_time_key_manager.rb
|
155
|
+
- lib/atomic_cache/storage/dalli.rb
|
156
|
+
- lib/atomic_cache/storage/instance_memory.rb
|
157
|
+
- lib/atomic_cache/storage/memory.rb
|
158
|
+
- lib/atomic_cache/storage/shared_memory.rb
|
159
|
+
- lib/atomic_cache/storage/store.rb
|
160
|
+
- lib/atomic_cache/version.rb
|
161
|
+
homepage: https://github.com/ibotta/atomic_cache
|
162
|
+
licenses:
|
163
|
+
- apache 2.0
|
164
|
+
metadata: {}
|
165
|
+
post_install_message:
|
166
|
+
rdoc_options: []
|
167
|
+
require_paths:
|
168
|
+
- lib
|
169
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - ">="
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
175
|
+
requirements:
|
176
|
+
- - ">"
|
177
|
+
- !ruby/object:Gem::Version
|
178
|
+
version: 1.3.1
|
179
|
+
requirements: []
|
180
|
+
rubyforge_project:
|
181
|
+
rubygems_version: 2.6.11
|
182
|
+
signing_key:
|
183
|
+
specification_version: 4
|
184
|
+
summary: summary
|
185
|
+
test_files: []
|