mondrian_redis_segment_cache 0.2.0-java → 0.3.0-java

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 896185519afb0d52f37a79e5025257bdf5dfbc5c
4
- data.tar.gz: 1bb17d24bf9ff9b6e93a43ab6eea7b3d819bc937
3
+ metadata.gz: 97fcf8346cd45a212d99ccefbf418c46e2b8937a
4
+ data.tar.gz: 851f15a091b8d16065d8faa954b5df564d1e7f08
5
5
  SHA512:
6
- metadata.gz: 800116baba8a0b27f294f247543e81a970f5d73926e68e98ae3e03c48f77dd3aa59667b3ccf49d7d0ea3feb68d13988fa67e8f883d429e02181f320e247ae412
7
- data.tar.gz: 33828588996fb1ac33f1d7d598de0b8949c8ffe7f5845e1823556ab9c2db3bbcca0de964e65b8f52f9a6b43f845ae11341a9a44c82f51f4688c1b2209d9b868d
6
+ metadata.gz: e31c59458a901c35683e2fa250b37e3c5a6f75ab680087214f6802ace7db9b1f20031abceff1d12ba1804d2d43ef3d62153436bf7de755442c87d93ba0aeff13
7
+ data.tar.gz: 0a3a82cb519cbe868c8acac5e1cdc3fdc567218b81e660fa44d7c2e6d55ea5ab0e16959566948f276076908f299a13ec9af7cbb2048f3992e6c543bd22ac8d53
data/README.md CHANGED
@@ -7,15 +7,10 @@ examples of other implementations are in the links below.
7
7
  In order to use Mondrian with Redis (our preferred caching layer) and Ruby (our preferred language -- Jruby) we had
8
8
  to implement the SegmentCache interface from Mondrian and use the Redis notifications api.
9
9
 
10
- Mondrian's segment cache needs to be able to get/set/remove cache items and also get any updates from the caching server
11
- as other nodes are getting/setting/removing entries. This means that we need to use both the notifications and subscribe
12
- api's from Redis.
13
-
14
10
  http://stackoverflow.com/questions/17533594/implementing-a-mondrian-shared-segmentcache
15
11
  http://mondrian.pentaho.com/api/mondrian/spi/SegmentCache.html
16
12
  https://github.com/pentaho/mondrian/blob/master/src/main/mondrian/rolap/cache/MemorySegmentCache.java
17
13
  https://github.com/webdetails/cdc
18
- http://redis.io/topics/notifications
19
14
 
20
15
  ## Installation
21
16
 
@@ -47,19 +42,6 @@ MONDRIAN_SEGMENT_CACHE = ::MondrianRedisSegmentCache::Cache.new(MONDRIAN_REDIS_C
47
42
  ::Java::MondrianSpi::SegmentCache::SegmentCacheInjector::add_cache(MONDRIAN_SEGMENT_CACHE)
48
43
  ```
49
44
 
50
- In Redis we use the notifications api, so you must turn it on!
51
- It is off by default because it is a new feature and can be CPU intensive. Redis does a ton, so there is a minimum of notifications
52
- that must be turned on for this gem to work.
53
-
54
- `notify-keyspace-events Egex$`
55
-
56
- This tells Redis to publish keyevent events (which means we can subscribe to things like set/del) and to publish the generic commands
57
- (like DEL, EXPIRE) and finally String commands (like SET)
58
-
59
- The SegmentCache uses these notifications to keep Mondrian in sync across your Mondrian instances.
60
- It also eager loads the current cached items into the listeners when they are added to the cache. This allows
61
- an existing cache to be reused between deploys.
62
-
63
45
  Cache expiry is handled by the options `:ttl` and `:expires_at`
64
46
 
65
47
  If you want a static ttl (time to live) then each key that is inserted will be set to expire after the ttl completes. This is
@@ -1,4 +1,5 @@
1
1
  require 'redis'
2
+ require 'concurrent'
2
3
  require 'mondrian_redis_segment_cache/created_event'
3
4
  require 'mondrian_redis_segment_cache/deleted_event'
4
5
 
@@ -6,15 +7,8 @@ module MondrianRedisSegmentCache
6
7
  class Cache
7
8
  include Java::MondrianSpi::SegmentCache
8
9
 
9
- attr_reader :created_listener_connection,
10
- :deleted_listener_connection,
11
- :evicted_listener_connection,
12
- :expired_listener_connection,
13
- :created_listener_thread,
14
- :deleted_listener_thread,
15
- :evicted_listener_thread,
16
- :expired_listener_thread,
17
- :listeners,
10
+ attr_reader :listeners,
11
+ :local_cache_set,
18
12
  :mondrian_redis,
19
13
  :options
20
14
 
@@ -25,15 +19,22 @@ module MondrianRedisSegmentCache
25
19
  #
26
20
  def initialize(mondrian_redis_connection, new_options = {})
27
21
  @mondrian_redis = mondrian_redis_connection
28
- @created_listener_connection = ::Redis.new(client_options)
29
- @deleted_listener_connection = ::Redis.new(client_options)
30
- @evicted_listener_connection = ::Redis.new(client_options)
31
- @expired_listener_connection = ::Redis.new(client_options)
32
22
  @options = Marshal.load(Marshal.dump(new_options))
23
+ @listeners = Set.new
24
+ @local_cache_set = Set.new
25
+
26
+ ##
27
+ # Having a TimerTask reconcile every 5 minutes so the local listeners are eventually consistent with
28
+ # respect to what is in the cache and what has been done .... allows us to get rid of the event
29
+ # subscribers in the redis API ... consider the job to have timed out after 45 seconds
30
+ @reconcile_task = ::Concurrent::TimerTask.new(:execution_interval => 360, :timeout_interval => 45) do
31
+ reconcile_set_and_keys
32
+ reconcile_local_set_with_redis
33
+ end
33
34
 
34
- reset_listeners
35
- start
35
+ @reconcile_task.execute
36
36
  reconcile_set_and_keys
37
+ reconcile_local_set_with_redis
37
38
  end
38
39
 
39
40
  ##
@@ -41,52 +42,19 @@ module MondrianRedisSegmentCache
41
42
  #
42
43
  def addListener(segment_cache_listener)
43
44
  listeners << segment_cache_listener
44
- eager_load_listener(segment_cache_listener)
45
- end
46
-
47
- # returns boolean
48
- # takes mondrian.spi.SegmentHeader
49
- def contains(segment_header)
50
- segment_header.description # Hazel adapter says this affects serialization
51
- header_base64 = segment_header_to_base64(segment_header)
52
-
53
- if header_base64
54
- return mondrian_redis.exists(header_base64)
55
- end
56
-
57
- return false
58
- end
59
-
60
- def created_event_key
61
- @created_event_key ||= "__keyevent@#{client_options[:db]}__:set"
62
- end
63
-
64
- def deleted_event_key
65
- @deleted_event_key ||= "__keyevent@#{client_options[:db]}__:del"
66
- end
67
-
68
- def evicted_event_key
69
- @evicted_event_key ||= "__keyevent@#{client_options[:db]}__:evicted"
70
- end
71
-
72
- def expired_event_key
73
- @expired_event_key ||= "__keyevent@#{client_options[:db]}__:expired"
74
- end
75
-
76
- def eager_load_listener(listener)
77
- mondrian_redis.sscan_each(SEGMENT_HEADERS_SET_KEY) do |segment_header_base64|
78
- publish_created_to_listener(segment_header_base64, listener)
79
- end
80
45
  end
81
46
 
82
47
  # returns mondrian.spi.SegmentBody
83
48
  # takes mondrian.spi.SegmentHeader
84
49
  def get(segment_header)
85
- segment_header.description # Hazel adapter says this affects serialization
50
+ segment_header.getDescription # Hazel adapter says this affects serialization
86
51
  header_base64 = segment_header_to_base64(segment_header)
87
52
 
88
53
  if header_base64
89
- body_base64 = mondrian_redis.get(header_base64)
54
+ body_base64 = mondrian_redis.with do |connection|
55
+ connection.get(header_base64)
56
+ end
57
+
90
58
  return segment_body_from_base64(body_base64)
91
59
  end
92
60
 
@@ -97,83 +65,52 @@ module MondrianRedisSegmentCache
97
65
  def getSegmentHeaders()
98
66
  segment_headers = ::Java::JavaUtil::ArrayList.new
99
67
 
100
- mondrian_redis.sscan_each(SEGMENT_HEADERS_SET_KEY) do |segment_header_base64|
101
- segment_header = segment_header_from_base64(segment_header_base64)
102
-
103
- if segment_header
104
- segment_headers << segment_header
68
+ mondrian_redis.with do |connection|
69
+ connection.sscan_each(SEGMENT_HEADERS_SET_KEY) do |segment_header_base64|
70
+ segment_header = segment_header_from_base64(segment_header_base64)
71
+ segment_headers << segment_header if segment_header
105
72
  end
106
73
  end
107
74
 
108
75
  return segment_headers
109
76
  end
110
77
 
111
- def publish_created_to_listener(message, listener)
112
- segment_header = segment_header_from_base64(message)
113
-
114
- if segment_header
115
- created_event = ::MondrianRedisSegmentCache::CreatedEvent.new(segment_header)
116
- listener.handle(created_event)
117
- end
118
-
119
- check_listener_threads
120
- end
121
-
122
- def publish_created_to_listeners(message)
123
- listeners.each do |listener|
124
- publish_created_to_listener(message, listener)
125
- end
126
-
127
- check_listener_threads
128
- end
129
-
130
- def publish_deleted_to_listener(message, listener)
131
- segment_header = segment_header_from_base64(message)
132
-
133
- if segment_header
134
- deleted_event = ::MondrianRedisSegmentCache::DeletedEvent.new(segment_header)
135
- listener.handle(deleted_event)
136
- end
137
-
138
- check_listener_threads
139
- end
140
-
141
- def publish_deleted_to_listeners(message)
142
- listeners.each do |listener|
143
- publish_deleted_to_listener(message, listener)
144
- end
145
-
146
- # Each server can tell the Set to remove the key as it may be expired
147
- if mondrian_redis.sismember(SEGMENT_HEADERS_SET_KEY, message)
148
- mondrian_redis.srem(SEGMENT_HEADERS_SET_KEY, message)
149
- end
150
-
151
- check_listener_threads
152
- end
153
- alias_method :publish_evicted_to_listeners, :publish_deleted_to_listeners
154
- alias_method :publish_expired_to_listeners, :publish_deleted_to_listeners
155
-
156
78
  def put(segment_header, segment_body)
157
- segment_header.description # Hazel adapter says this affects serialization
79
+ set_success = nil
80
+ segment_header.getDescription # Hazel adapter says this affects serialization
158
81
  header_base64 = segment_header_to_base64(segment_header)
159
82
  body_base64 = segment_body_to_base64(segment_body)
160
- mondrian_redis.sadd(SEGMENT_HEADERS_SET_KEY, header_base64)
83
+ @local_cache_set << header_base64
84
+ mondrian_redis.with do |connection|
85
+ connection.sadd(SEGMENT_HEADERS_SET_KEY, header_base64)
86
+ end
161
87
 
162
88
  if has_expiry?
163
- set_success = mondrian_redis.setex(header_base64, expires_in_seconds, body_base64)
89
+ set_success = mondrian_redis.with do |connection|
90
+ connection.setex(header_base64, expires_in_seconds, body_base64)
91
+ end
164
92
  else
165
- set_success = mondrian_redis.set(header_base64, body_base64)
93
+ set_success = mondrian_redis.with do |connection|
94
+ connection.set(header_base64, body_base64)
95
+ end
166
96
  end
167
97
 
98
+ publish_created_to_listeners(header_base64)
168
99
  return ("#{set_success}".upcase == "OK" || set_success == true) # weird polymorphic return ?
169
100
  end
170
101
 
171
102
  def remove(segment_header)
172
- segment_header.description # Hazel adapter says this affects serialization
103
+ segment_header.getDescription # Hazel adapter says this affects serialization
173
104
  header_base64 = segment_header_to_base64(segment_header)
174
- mondrian_redis.srem(SEGMENT_HEADERS_SET_KEY, header_base64)
175
- deleted_keys = mondrian_redis.del(header_base64)
105
+ mondrian_redis.with do |connection|
106
+ connection.srem(SEGMENT_HEADERS_SET_KEY, header_base64)
107
+ end
108
+
109
+ deleted_keys = mondrian_redis.with do |connection|
110
+ connection.del(header_base64)
111
+ end
176
112
 
113
+ publish_deleted_to_listeners(header_base64)
177
114
  return deleted_keys >= 1
178
115
  end
179
116
 
@@ -181,35 +118,12 @@ module MondrianRedisSegmentCache
181
118
  listeners.delete(segment_cache_listener)
182
119
  end
183
120
 
184
- def reset_listeners
185
- @listeners = Set.new
186
- end
187
-
188
- def shutdown!
189
- # Ouch, why so harsh?
190
- created_listener_thread.kill if created_listener_thread && created_listener_thread.alive?
191
- deleted_listener_thread.kill if deleted_listener_thread && deleted_listener_thread.alive?
192
- evicted_listener_thread.kill if evicted_listener_thread && evicted_listener_thread.alive?
193
- expired_listener_thread.kill if expired_listener_thread && expired_listener_thread.alive?
194
- end
195
-
196
- def start
197
- check_listener_threads
198
- end
199
-
200
121
  def supportsRichIndex()
201
122
  true # this is why we are serializing the headers to base64
202
123
  end
203
124
 
204
125
  def tearDown()
205
- if options[:delete_all_on_tear_down]
206
- # Remove all of the headers and the set that controls them
207
- mondrian_redis.sscan_each(SEGMENT_HEADERS_SET_KEY) do |segment_header_base64|
208
- mondrian_redis.del(segment_header_base64)
209
- end
210
-
211
- mondrian_redis.del(SEGMENT_HEADERS_SET_KEY)
212
- end
126
+ #no-op
213
127
  end
214
128
 
215
129
  private
@@ -217,26 +131,6 @@ module MondrianRedisSegmentCache
217
131
  ##
218
132
  # Private Instance Methods
219
133
  #
220
- def check_listener_threads
221
- register_created_listener if !created_listener_thread.respond_to?(:alive?) || !created_listener_thread.alive?
222
- register_deleted_listener if !deleted_listener_thread.respond_to?(:alive?) || !deleted_listener_thread.alive?
223
- register_expired_listener if !expired_listener_thread.respond_to?(:alive?) || !expired_listener_thread.alive?
224
- register_evicted_listener if !evicted_listener_thread.respond_to?(:alive?) || !evicted_listener_thread.alive?
225
- end
226
-
227
- def client_options
228
- # Redis 3.0.4 does not have options where 3.1 does
229
- unless mondrian_redis.client.respond_to?(:options)
230
- class << mondrian_redis.client
231
- def options
232
- @options
233
- end
234
- end
235
- end
236
-
237
- return mondrian_redis.client.options
238
- end
239
-
240
134
  def expires_in_seconds
241
135
  return options[:ttl] if options[:ttl]
242
136
 
@@ -248,7 +142,7 @@ module MondrianRedisSegmentCache
248
142
  expires_at = ::Time.new(now.year, now.month, now.day, options[:expires_at])
249
143
  end
250
144
 
251
- difference_from_now = now.to_i - expires_at.to_i
145
+ difference_from_now = expires_at.to_i - now.to_i
252
146
 
253
147
  until difference_from_now > 0 do
254
148
  difference_from_now = difference_from_now + 86_400 # already passed today, move to time tomorrow
@@ -261,55 +155,74 @@ module MondrianRedisSegmentCache
261
155
  options.has_key?(:ttl) || options.has_key?(:expires_at)
262
156
  end
263
157
 
264
- def reconcile_set_and_keys
265
- mondrian_redis.sscan_each(SEGMENT_HEADERS_SET_KEY) do |segment_header_base64|
266
- # Spin through Header Set and remove any keys that are not in redis at all (they may have been deleted while offline)
267
- unless mondrian_redis.exists(segment_header_base64)
268
- mondrian_redis.srem(SEGMENT_HEADERS_SET_KEY, segment_header_base64)
269
- end
158
+ def publish_created_to_listener(message, listener)
159
+ segment_header = segment_header_from_base64(message)
160
+
161
+ if segment_header
162
+ created_event = ::MondrianRedisSegmentCache::CreatedEvent.new(segment_header)
163
+ listener.handle(created_event)
270
164
  end
271
165
  end
272
166
 
273
- def register_created_listener
274
- @created_listener_thread = Thread.new(created_listener_connection, self) do |created_redis_connection, mondrian_cache|
275
- created_redis_connection.subscribe(mondrian_cache.created_event_key) do |on|
276
- on.message do |channel, message|
277
- mondrian_cache.publish_created_to_listeners(message)
278
- end
279
- end
167
+ def publish_created_to_listeners(message)
168
+ listeners.each do |listener|
169
+ publish_created_to_listener(message, listener)
280
170
  end
281
171
  end
282
172
 
283
- def register_deleted_listener
284
- @deleted_listener_thread = Thread.new(deleted_listener_connection, self) do |deleted_redis_connection, mondrian_cache|
285
- deleted_redis_connection.subscribe(mondrian_cache.deleted_event_key) do |on|
286
- on.message do |channel, message|
287
- mondrian_cache.publish_deleted_to_listeners(message)
288
- end
289
- end
173
+ def publish_deleted_to_listener(message, listener)
174
+ segment_header = segment_header_from_base64(message)
175
+
176
+ if segment_header
177
+ deleted_event = ::MondrianRedisSegmentCache::DeletedEvent.new(segment_header)
178
+ listener.handle(deleted_event)
290
179
  end
291
180
  end
292
181
 
293
- def register_expired_listener
294
- @expired_listener_thread = Thread.new(expired_listener_connection, self) do |expired_redis_connection, mondrian_cache|
295
- expired_redis_connection.subscribe(mondrian_cache.expired_event_key) do |on|
296
- on.message do |channel, message|
297
- mondrian_cache.publish_expired_to_listeners(message)
298
- end
299
- end
182
+ def publish_deleted_to_listeners(message)
183
+ listeners.each do |listener|
184
+ publish_deleted_to_listener(message, listener)
300
185
  end
301
186
  end
302
187
 
303
- def register_evicted_listener
304
- @evicted_listener_thread = Thread.new(evicted_listener_connection, self) do |evicted_redis_connection, mondrian_cache|
305
- evicted_redis_connection.subscribe(mondrian_cache.evicted_event_key) do |on|
306
- on.message do |channel, message|
307
- mondrian_cache.publish_evicted_to_listeners(message)
308
- end
188
+ def reconcile_local_set_with_redis
189
+ remote_set = Set.new
190
+
191
+ mondrian_redis.with do |connection|
192
+ connection.sscan_each(SEGMENT_HEADERS_SET_KEY) do |segment_header_base64|
193
+ remote_set << segment_header_base64
309
194
  end
310
195
  end
196
+
197
+ remote_added_keys = remote_set - local_cache_set
198
+ remote_removed_keys = local_cache_set - remote_set
199
+
200
+ remote_added_keys.each do |remote_added_key|
201
+ @local_cache_set << remote_added_key
202
+ publish_created_to_listeners(remote_added_key)
203
+ end
204
+
205
+ remote_removed_keys.each do |remote_removed_key|
206
+ @local_cache_set.delete(remote_removed_key)
207
+ publish_deleted_to_listeners(remote_removed_key)
208
+ end
311
209
  end
312
210
 
211
+ def reconcile_set_and_keys
212
+ headers = []
213
+ mondrian_redis.with do |connection|
214
+ connection.sscan_each(SEGMENT_HEADERS_SET_KEY) do |segment_header_base64|
215
+ headers << segment_header_base64
216
+ end
217
+ end
218
+
219
+ mondrian_redis.with do |connection|
220
+ headers.each do |header|
221
+ # Spin through Header Set and remove any keys that are not in redis at all (they may have been deleted while offline)
222
+ connection.srem(SEGMENT_HEADERS_SET_KEY, header) unless connection.exists(header)
223
+ end
224
+ end
225
+ end
313
226
 
314
227
  def segment_body_from_base64(segment_body_base64)
315
228
  return nil unless segment_body_base64
@@ -1,3 +1,3 @@
1
1
  module MondrianRedisSegmentCache
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.0"
3
3
  end
@@ -21,6 +21,7 @@ Gem::Specification.new do |gem|
21
21
  gem.add_dependency "redis"
22
22
  gem.add_dependency "java_to_base64"
23
23
  gem.add_dependency "mondrian-olap"
24
+ gem.add_dependency "concurrent-ruby"
24
25
 
25
26
  gem.add_development_dependency "bundler"
26
27
  gem.add_development_dependency "mocha"
metadata CHANGED
@@ -1,113 +1,127 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mondrian_redis_segment_cache
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: java
6
6
  authors:
7
7
  - Brandon Dewitt
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-09-19 00:00:00.000000000 Z
11
+ date: 2017-01-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '0'
14
19
  name: redis
20
+ prerelease: false
21
+ type: :runtime
15
22
  version_requirements: !ruby/object:Gem::Requirement
16
23
  requirements:
17
- - - '>='
24
+ - - ">="
18
25
  - !ruby/object:Gem::Version
19
26
  version: '0'
27
+ - !ruby/object:Gem::Dependency
20
28
  requirement: !ruby/object:Gem::Requirement
21
29
  requirements:
22
- - - '>='
30
+ - - ">="
23
31
  - !ruby/object:Gem::Version
24
32
  version: '0'
33
+ name: java_to_base64
25
34
  prerelease: false
26
35
  type: :runtime
27
- - !ruby/object:Gem::Dependency
28
- name: java_to_base64
29
36
  version_requirements: !ruby/object:Gem::Requirement
30
37
  requirements:
31
- - - '>='
38
+ - - ">="
32
39
  - !ruby/object:Gem::Version
33
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
34
42
  requirement: !ruby/object:Gem::Requirement
35
43
  requirements:
36
- - - '>='
44
+ - - ">="
37
45
  - !ruby/object:Gem::Version
38
46
  version: '0'
47
+ name: mondrian-olap
39
48
  prerelease: false
40
49
  type: :runtime
41
- - !ruby/object:Gem::Dependency
42
- name: mondrian-olap
43
50
  version_requirements: !ruby/object:Gem::Requirement
44
51
  requirements:
45
- - - '>='
52
+ - - ">="
46
53
  - !ruby/object:Gem::Version
47
54
  version: '0'
55
+ - !ruby/object:Gem::Dependency
48
56
  requirement: !ruby/object:Gem::Requirement
49
57
  requirements:
50
- - - '>='
58
+ - - ">="
51
59
  - !ruby/object:Gem::Version
52
60
  version: '0'
61
+ name: concurrent-ruby
53
62
  prerelease: false
54
63
  type: :runtime
55
- - !ruby/object:Gem::Dependency
56
- name: bundler
57
64
  version_requirements: !ruby/object:Gem::Requirement
58
65
  requirements:
59
- - - '>='
66
+ - - ">="
60
67
  - !ruby/object:Gem::Version
61
68
  version: '0'
69
+ - !ruby/object:Gem::Dependency
62
70
  requirement: !ruby/object:Gem::Requirement
63
71
  requirements:
64
- - - '>='
72
+ - - ">="
65
73
  - !ruby/object:Gem::Version
66
74
  version: '0'
75
+ name: bundler
67
76
  prerelease: false
68
77
  type: :development
69
- - !ruby/object:Gem::Dependency
70
- name: mocha
71
78
  version_requirements: !ruby/object:Gem::Requirement
72
79
  requirements:
73
- - - '>='
80
+ - - ">="
74
81
  - !ruby/object:Gem::Version
75
82
  version: '0'
83
+ - !ruby/object:Gem::Dependency
76
84
  requirement: !ruby/object:Gem::Requirement
77
85
  requirements:
78
- - - '>='
86
+ - - ">="
79
87
  - !ruby/object:Gem::Version
80
88
  version: '0'
89
+ name: mocha
81
90
  prerelease: false
82
91
  type: :development
83
- - !ruby/object:Gem::Dependency
84
- name: pry
85
92
  version_requirements: !ruby/object:Gem::Requirement
86
93
  requirements:
87
- - - '>='
94
+ - - ">="
88
95
  - !ruby/object:Gem::Version
89
96
  version: '0'
97
+ - !ruby/object:Gem::Dependency
90
98
  requirement: !ruby/object:Gem::Requirement
91
99
  requirements:
92
- - - '>='
100
+ - - ">="
93
101
  - !ruby/object:Gem::Version
94
102
  version: '0'
103
+ name: pry
95
104
  prerelease: false
96
105
  type: :development
97
- - !ruby/object:Gem::Dependency
98
- name: rake
99
106
  version_requirements: !ruby/object:Gem::Requirement
100
107
  requirements:
101
- - - '>='
108
+ - - ">="
102
109
  - !ruby/object:Gem::Version
103
110
  version: '0'
111
+ - !ruby/object:Gem::Dependency
104
112
  requirement: !ruby/object:Gem::Requirement
105
113
  requirements:
106
- - - '>='
114
+ - - ">="
107
115
  - !ruby/object:Gem::Version
108
116
  version: '0'
117
+ name: rake
109
118
  prerelease: false
110
119
  type: :development
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
111
125
  description: Segment Cache for Mondrian written in JRuby with Redis as the cache store
112
126
  email:
113
127
  - brandonsdewitt@gmail.com
@@ -115,7 +129,7 @@ executables: []
115
129
  extensions: []
116
130
  extra_rdoc_files: []
117
131
  files:
118
- - .gitignore
132
+ - ".gitignore"
119
133
  - Gemfile
120
134
  - LICENSE.txt
121
135
  - README.md
@@ -137,17 +151,17 @@ require_paths:
137
151
  - lib
138
152
  required_ruby_version: !ruby/object:Gem::Requirement
139
153
  requirements:
140
- - - '>='
154
+ - - ">="
141
155
  - !ruby/object:Gem::Version
142
156
  version: '0'
143
157
  required_rubygems_version: !ruby/object:Gem::Requirement
144
158
  requirements:
145
- - - '>='
159
+ - - ">="
146
160
  - !ruby/object:Gem::Version
147
161
  version: '0'
148
162
  requirements: []
149
163
  rubyforge_project:
150
- rubygems_version: 2.2.2
164
+ rubygems_version: 2.4.8
151
165
  signing_key:
152
166
  specification_version: 4
153
167
  summary: Segment Cache for Mondrian written in JRuby with Redis as the cache store