mondrian_redis_segment_cache 0.2.0-java → 0.3.0-java
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/README.md +0 -18
- data/lib/mondrian_redis_segment_cache/cache.rb +101 -188
- data/lib/mondrian_redis_segment_cache/version.rb +1 -1
- data/mondrian_redis_segment_cache.gemspec +1 -0
- metadata +46 -32
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 97fcf8346cd45a212d99ccefbf418c46e2b8937a
|
4
|
+
data.tar.gz: 851f15a091b8d16065d8faa954b5df564d1e7f08
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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 :
|
10
|
-
:
|
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
|
-
|
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.
|
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.
|
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.
|
101
|
-
|
102
|
-
|
103
|
-
|
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
|
-
|
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
|
-
|
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.
|
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.
|
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.
|
103
|
+
segment_header.getDescription # Hazel adapter says this affects serialization
|
173
104
|
header_base64 = segment_header_to_base64(segment_header)
|
174
|
-
mondrian_redis.
|
175
|
-
|
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
|
-
|
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 =
|
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
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
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
|
274
|
-
|
275
|
-
|
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
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
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
|
294
|
-
|
295
|
-
|
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
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
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
|
@@ -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.
|
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:
|
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.
|
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
|