rhoconnect 3.3.6 → 3.4.2
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.
- data/CHANGELOG.md +40 -4
- data/Gemfile +2 -2
- data/Gemfile.lock +27 -25
- data/bench/benchapp/Gemfile +7 -27
- data/bench/benchapp/config.ru +9 -31
- data/bench/blobapp/Gemfile +7 -27
- data/bench/blobapp/config.ru +9 -29
- data/bench/lib/bench.rb +8 -1
- data/bench/lib/bench/test_data.rb +4 -1
- data/bench/scripts/blob_cud_script.rb +4 -0
- data/bench/scripts/cud_script.rb +7 -1
- data/bench/scripts/helpers.rb +1 -1
- data/bench/scripts/test_query_script.rb +20 -7
- data/bench/spec/bench_spec_helper.rb +3 -1
- data/bin/rhoconnect +22 -12
- data/commands/{commands/dtach_commands → dtach}/dtach_about.rb +0 -0
- data/commands/{commands/dtach_commands → dtach}/dtach_install.rb +0 -0
- data/commands/{commands/redis_commands → dtach}/redis_attach.rb +0 -0
- data/commands/execute.rb +14 -15
- data/commands/generators/update.rb +26 -0
- data/commands/{commands/redis_commands → redis}/redis_about.rb +0 -0
- data/commands/redis/redis_download.rb +13 -0
- data/commands/redis/redis_install.rb +26 -0
- data/commands/{commands/redis_commands → redis}/redis_make.rb +0 -0
- data/commands/{commands/redis_commands → redis}/redis_restart.rb +3 -2
- data/commands/{commands/redis_commands → redis}/redis_start.rb +0 -0
- data/commands/{commands/redis_commands → redis}/redis_startbg.rb +0 -0
- data/commands/{commands/redis_commands → redis}/redis_stop.rb +3 -2
- data/commands/{commands/rhoconnect → rhoconnect}/clean_start.rb +0 -0
- data/commands/{commands/rhoconnect → rhoconnect}/config.rb +7 -2
- data/commands/{commands/rhoconnect → rhoconnect}/create_user.rb +0 -0
- data/commands/{commands/rhoconnect → rhoconnect}/delete_device.rb +0 -0
- data/commands/{commands/rhoconnect → rhoconnect}/delete_user.rb +0 -0
- data/commands/{commands/rhoconnect → rhoconnect}/flushdb.rb +4 -4
- data/commands/{commands/rhoconnect → rhoconnect}/get_token.rb +0 -0
- data/commands/{commands/rhoconnect → rhoconnect}/reset.rb +0 -0
- data/commands/{commands/rhoconnect → rhoconnect}/reset_refresh.rb +0 -0
- data/commands/{commands/rhoconnect → rhoconnect}/restart.rb +0 -0
- data/commands/{commands/rhoconnect → rhoconnect}/secret.rb +0 -0
- data/commands/{commands/rhoconnect → rhoconnect}/set_admin_password.rb +0 -0
- data/commands/{commands/rhoconnect → rhoconnect}/spec.rb +0 -0
- data/commands/rhoconnect/start.rb +27 -0
- data/commands/{commands/rhoconnect → rhoconnect}/startbg.rb +0 -0
- data/commands/{commands/rhoconnect → rhoconnect}/startdebug.rb +2 -2
- data/commands/{commands/rhoconnect → rhoconnect}/stop.rb +3 -4
- data/commands/{commands/rhoconnect → rhoconnect}/version.rb +0 -0
- data/commands/{commands/rhoconnect → rhoconnect}/web.rb +0 -0
- data/commands/rhoconnect_attach/attach.rb +10 -0
- data/commands/rhoconnect_console/console.rb +16 -0
- data/commands/{commands/rhoconnect → rhoconnect_console}/console_helper.rb +0 -0
- data/commands/{commands/rhoconnect → rhoconnect_war}/war.rb +0 -0
- data/commands/{commands/redis_commands → utilities}/redis_runner.rb +22 -19
- data/commands/utilities/utilities.rb +6 -0
- data/doc/benchmarks.txt +2 -2
- data/doc/bulk-sync.txt +12 -1
- data/doc/client-java.txt +3 -3
- data/doc/client-objc.txt +1 -1
- data/doc/client.txt +5 -5
- data/doc/command-line.txt +80 -135
- data/doc/deploying.txt +119 -12
- data/doc/extending-rhoconnect-server.txt +1 -1
- data/doc/heroku-addon.txt +119 -23
- data/doc/install.txt +101 -39
- data/doc/java-plugin.txt +2 -2
- data/doc/licensing.txt +1 -1
- data/doc/plugin-intro.txt +3 -1
- data/doc/preparing-production.txt +4 -4
- data/doc/public/cli.txt +2 -2
- data/doc/push-backend-setup.txt +11 -1
- data/doc/push-client-setup.txt +72 -2
- data/doc/push-server-setup.txt +129 -8
- data/doc/rails-plugin.txt +245 -40
- data/doc/rest-api.txt +10 -6
- data/doc/rhoconnect-calculator.txt +237 -0
- data/doc/rhoconnect-redis-stack.txt +35 -0
- data/doc/session-and-configuration.txt +24 -0
- data/doc/settings.txt +51 -41
- data/doc/source-adapters.txt +45 -45
- data/doc/stats-middleware.txt +2 -2
- data/doc/supported-platforms.txt +6 -6
- data/doc/testing.txt +2 -2
- data/doc/tutorial.txt +63 -63
- data/examples/simple/Gemfile +7 -35
- data/examples/simple/config.ru +8 -26
- data/examples/simple/sources/product.rb +6 -6
- data/generators/rhoconnect.rb +5 -0
- data/generators/templates/application/Gemfile +7 -37
- data/generators/templates/application/Rakefile +8 -0
- data/generators/templates/application/config.ru +12 -31
- data/generators/templates/application/rcgemfile +44 -0
- data/generators/templates/application/settings/settings.yml +7 -5
- data/install.sh +4 -4
- data/installer/unix-like/create_texts.rb +7 -2
- data/installer/unix-like/rho_connect_install_constants.rb +2 -2
- data/installer/unix-like/rho_connect_install_installers.rb +1 -16
- data/lib/rhoconnect.rb +51 -38
- data/lib/rhoconnect/api/app/query.rb +4 -1
- data/lib/rhoconnect/api/app/search.rb +4 -1
- data/lib/rhoconnect/api/client/list_client_docs.rb +3 -1
- data/lib/rhoconnect/api/user/ping.rb +1 -5
- data/lib/rhoconnect/application/init.rb +43 -0
- data/lib/rhoconnect/async.rb +11 -6
- data/lib/rhoconnect/client_sync.rb +30 -37
- data/lib/rhoconnect/document.rb +4 -0
- data/lib/rhoconnect/graph_helper.rb +74 -56
- data/lib/rhoconnect/middleware/helpers.rb +4 -0
- data/lib/rhoconnect/ping.rb +1 -0
- data/lib/rhoconnect/ping/gcm.rb +58 -0
- data/lib/rhoconnect/predefined_adapters/bench_adapter.rb +7 -1
- data/lib/rhoconnect/source.rb +70 -56
- data/lib/rhoconnect/source_sync.rb +33 -5
- data/lib/rhoconnect/store.rb +358 -110
- data/lib/rhoconnect/user.rb +8 -0
- data/lib/rhoconnect/utilities.rb +16 -14
- data/lib/rhoconnect/version.rb +1 -1
- data/lib/rhoconnect/web-console/models/client.js +1 -1
- data/lib/rhoconnect/web-console/public/UNVR67bold.ttf +0 -0
- data/lib/rhoconnect/web-console/public/bootstrap.css +6 -0
- data/lib/rhoconnect/web-console/public/logo.png +0 -0
- data/lib/rhoconnect/web-console/server.rb +13 -11
- data/lib/rhoconnect/web-console/templates/index.erb +5 -5
- data/lib/rhoconnect/web-console/templates/jqplot.erb +1 -0
- data/lib/rhoconnect/web-console/views/doc.js +0 -4
- data/lib/rhoconnect/web-console/views/home.js +2 -1
- data/lib/rhoconnect/web-console/views/new_ping.js +11 -6
- data/lib/rhoconnect/web-console/views/stats.js +9 -5
- data/rhoconnect.gemspec +6 -4
- data/spec/api/app/fast_update_spec.rb +2 -2
- data/spec/api/source/get_source_params_spec.rb +1 -0
- data/spec/apps/rhotestapp/settings/settings.yml +5 -5
- data/spec/client_sync_spec.rb +3 -14
- data/spec/perf/perf_spec_helper.rb +11 -7
- data/spec/perf/store_perf_spec.rb +88 -11
- data/spec/ping/gcm_spec.rb +99 -0
- data/spec/server/server_spec.rb +7 -0
- data/spec/server/stats_spec.rb +9 -2
- data/spec/source_sync_spec.rb +29 -0
- data/spec/spec_helper.rb +40 -38
- data/spec/stats/record_spec.rb +18 -9
- data/spec/store_spec.rb +128 -19
- data/spec/testdata/10000-data.txt +0 -0
- data/spec/testdata/5-data.txt +0 -0
- data/spec/testdata/5000-data.txt +0 -0
- data/tasks/jasmine.rake +1 -0
- data/tasks/redis.rake +16 -13
- metadata +71 -39
- data/commands/commands/redis_commands/redis_download.rb +0 -33
- data/commands/commands/redis_commands/redis_install.rb +0 -26
- data/commands/commands/rhoconnect/attach.rb +0 -8
- data/commands/commands/rhoconnect/console.rb +0 -15
- data/commands/commands/rhoconnect/start.rb +0 -18
- data/commands/utilities/dtach_installed.rb +0 -10
data/lib/rhoconnect/store.rb
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
require 'digest/sha1'
|
|
2
|
+
require 'set'
|
|
3
|
+
require 'connection_pool'
|
|
2
4
|
|
|
3
5
|
module Rhoconnect
|
|
4
6
|
|
|
@@ -18,7 +20,7 @@ module Rhoconnect
|
|
|
18
20
|
def create(server=nil)
|
|
19
21
|
@@db ||= _get_redis(server)
|
|
20
22
|
raise "Error connecting to Redis store." unless @@db and
|
|
21
|
-
(@@db.is_a?(Redis) or @@db.is_a?(Redis::Client))
|
|
23
|
+
(@@db.is_a?(Redis) or @@db.is_a?(Redis::Client) or @@db.is_a?(ConnectionPool::Wrapper))
|
|
22
24
|
end
|
|
23
25
|
|
|
24
26
|
def start_transaction
|
|
@@ -53,7 +55,7 @@ module Rhoconnect
|
|
|
53
55
|
end
|
|
54
56
|
|
|
55
57
|
def put_object(dockey, key, data={})
|
|
56
|
-
|
|
58
|
+
_put_objects(dockey, {key => data})
|
|
57
59
|
end
|
|
58
60
|
|
|
59
61
|
# Adds set with given data, replaces existing set
|
|
@@ -64,12 +66,7 @@ module Rhoconnect
|
|
|
64
66
|
flash_data(dockey) unless append
|
|
65
67
|
# Inserts a hash or array
|
|
66
68
|
if data.is_a?Hash
|
|
67
|
-
|
|
68
|
-
data.each do |key,value|
|
|
69
|
-
raise ArgumentError, "Invalid value object: #{value.inspect}. Hash is expected." unless value.is_a?(Hash)
|
|
70
|
-
_put_object(dockey, key, value)
|
|
71
|
-
end
|
|
72
|
-
end
|
|
69
|
+
_put_objects(dockey, data)
|
|
73
70
|
else
|
|
74
71
|
put_list(dockey,data,append)
|
|
75
72
|
end
|
|
@@ -81,8 +78,8 @@ module Rhoconnect
|
|
|
81
78
|
if dockey and data
|
|
82
79
|
flash_data(dockey) unless append
|
|
83
80
|
@@db.pipelined do
|
|
84
|
-
data.each do |
|
|
85
|
-
@@db.rpush(dockey,
|
|
81
|
+
data.each do |element|
|
|
82
|
+
@@db.rpush(dockey, element)
|
|
86
83
|
end
|
|
87
84
|
end
|
|
88
85
|
end
|
|
@@ -95,29 +92,45 @@ module Rhoconnect
|
|
|
95
92
|
return 0 unless dockey and data
|
|
96
93
|
|
|
97
94
|
new_object_count = 0
|
|
98
|
-
objs = get_objects(dockey, data.keys)
|
|
95
|
+
objs = get_objects(dockey, data.keys) || {}
|
|
96
|
+
|
|
97
|
+
collected_adds = {}
|
|
98
|
+
collected_rems = {}
|
|
99
|
+
my_bucket = nil
|
|
99
100
|
@@db.pipelined do
|
|
100
|
-
data.each do |key,
|
|
101
|
+
data.each do |key,obj|
|
|
101
102
|
is_create = objs[key].nil?
|
|
102
103
|
new_object_count += 1 if is_create
|
|
103
104
|
obj_bucket = _add_bucket_index(dockey, "#{_create_obj_index(key)}")
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
existing_element = setelement(key,attrib,objs[key][attrib])
|
|
111
|
-
if existing_element != new_element
|
|
112
|
-
@@db.srem(obj_bucket, existing_element)
|
|
113
|
-
@@db.sadd(obj_bucket, new_element)
|
|
114
|
-
end
|
|
115
|
-
else
|
|
116
|
-
@@db.sadd(obj_bucket, new_element)
|
|
117
|
-
end
|
|
105
|
+
|
|
106
|
+
# collect SREM (if object exists in DB)
|
|
107
|
+
unless is_create
|
|
108
|
+
old_element = set_obj_element(key,objs[key])
|
|
109
|
+
collected_rems[obj_bucket] ||= []
|
|
110
|
+
collected_rems[obj_bucket] << old_element
|
|
118
111
|
end
|
|
112
|
+
# update the object and collect SADD
|
|
113
|
+
objs[key] ||= {}
|
|
114
|
+
objs[key].merge!(obj)
|
|
115
|
+
|
|
116
|
+
new_element = set_obj_element(key,objs[key])
|
|
117
|
+
collected_adds[obj_bucket] ||= []
|
|
118
|
+
collected_adds[obj_bucket] << new_element
|
|
119
|
+
end
|
|
120
|
+
# process all SADD and SREM commands as one
|
|
121
|
+
# SREM must go first
|
|
122
|
+
collected_rems.each do |bucket, bucket_data|
|
|
123
|
+
@@db.srem(bucket, bucket_data)
|
|
124
|
+
end
|
|
125
|
+
collected_adds.each do |bucket, bucket_data|
|
|
126
|
+
@@db.sadd(bucket, bucket_data)
|
|
119
127
|
end
|
|
120
128
|
end
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
#data1 = @@db.smembers(my_bucket)
|
|
132
|
+
#puts "data1 is #{data1.inspect}"
|
|
133
|
+
|
|
121
134
|
new_object_count
|
|
122
135
|
end
|
|
123
136
|
|
|
@@ -125,28 +138,14 @@ module Rhoconnect
|
|
|
125
138
|
def delete_objects(dockey,data=[])
|
|
126
139
|
return 0 unless dockey and data
|
|
127
140
|
|
|
128
|
-
deleted_object_count = 0
|
|
129
141
|
objs = get_objects(dockey, data)
|
|
130
|
-
|
|
131
|
-
data.each do |id|
|
|
132
|
-
if _delete_object(dockey, id, objs[id])
|
|
133
|
-
deleted_object_count += 1
|
|
134
|
-
end
|
|
135
|
-
end
|
|
136
|
-
end
|
|
137
|
-
_cleanup_buckets(dockey, objs.keys)
|
|
138
|
-
deleted_object_count
|
|
142
|
+
_delete_objects(dockey, objs)
|
|
139
143
|
end
|
|
140
144
|
|
|
141
145
|
# Deletes data from a given doctype,source,user
|
|
142
146
|
def delete_data(dockey,data={})
|
|
143
147
|
if dockey and data
|
|
144
|
-
|
|
145
|
-
data.each do |key,value|
|
|
146
|
-
_delete_object(dockey, key, value)
|
|
147
|
-
end
|
|
148
|
-
end
|
|
149
|
-
_cleanup_buckets(dockey, data.keys)
|
|
148
|
+
_delete_objects(dockey, data)
|
|
150
149
|
end
|
|
151
150
|
true
|
|
152
151
|
end
|
|
@@ -180,15 +179,12 @@ module Rhoconnect
|
|
|
180
179
|
end
|
|
181
180
|
|
|
182
181
|
def get_object(dockey, key)
|
|
183
|
-
|
|
182
|
+
res = _get_objects(dockey, [key])
|
|
183
|
+
(res and res.size > 0) ? res.values[0] : nil
|
|
184
184
|
end
|
|
185
185
|
|
|
186
186
|
def get_objects(dockey, keys)
|
|
187
|
-
|
|
188
|
-
keys.each do |key|
|
|
189
|
-
res[key] = _get_object(dockey, key)
|
|
190
|
-
end if keys
|
|
191
|
-
res
|
|
187
|
+
_get_objects(dockey, keys)
|
|
192
188
|
end
|
|
193
189
|
|
|
194
190
|
# Retrieves set for given dockey,source,user
|
|
@@ -197,14 +193,18 @@ module Rhoconnect
|
|
|
197
193
|
if dockey
|
|
198
194
|
if type == Hash
|
|
199
195
|
buckets = _get_buckets(dockey)
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
196
|
+
members = @@db.pipelined do
|
|
197
|
+
buckets.each do |bucket|
|
|
198
|
+
@@db.smembers(bucket)
|
|
199
|
+
end if buckets
|
|
200
|
+
end
|
|
201
|
+
members.each do |elements|
|
|
202
|
+
elements.each do |element|
|
|
203
|
+
key,obj = get_obj_element(element)
|
|
204
|
+
res[key] = obj
|
|
205
|
+
#res[key].merge!({attrib => value})
|
|
206
|
+
end if elements
|
|
207
|
+
end if members
|
|
208
208
|
else
|
|
209
209
|
res = get_list(dockey)
|
|
210
210
|
end
|
|
@@ -221,35 +221,116 @@ module Rhoconnect
|
|
|
221
221
|
end
|
|
222
222
|
|
|
223
223
|
# Retrieves diff data hash between two sets
|
|
224
|
+
# each entry is in the form of DIFF_OBJ_ELEMENT => [OBJ_KEY, OBJ_DATA_PAIRS]
|
|
224
225
|
def get_diff_data(src_dockey,dst_dockey,p_size=nil)
|
|
225
226
|
res = {}
|
|
226
227
|
if src_dockey and dst_dockey
|
|
227
228
|
# obtain combined indices
|
|
228
229
|
indices = @@db.hgetall("#{dst_dockey}:indices")
|
|
229
|
-
indices.merge!(@@db.hgetall("#{dst_dockey}:indices"))
|
|
230
230
|
indices.keys.each do |index|
|
|
231
231
|
dst_bucket_name = "#{dst_dockey}:#{index}"
|
|
232
232
|
src_bucket_name = "#{src_dockey}:#{index}"
|
|
233
|
-
@@db.sdiff(dst_bucket_name,src_bucket_name)
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
233
|
+
diff_elements = @@db.sdiff(dst_bucket_name,src_bucket_name)
|
|
234
|
+
diff_elements.each do |element|
|
|
235
|
+
keypairs = get_obj_key_and_pairs(element)
|
|
236
|
+
next unless keypairs
|
|
237
|
+
res[element] = keypairs
|
|
238
|
+
return res if p_size and (res.size >= p_size)
|
|
237
239
|
end
|
|
238
|
-
break if p_size and (res.size >= p_size)
|
|
239
240
|
end
|
|
240
241
|
end
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
242
|
+
res
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
def get_inserts_deletes(inserts_elements_map, deletes_elements_map)
|
|
246
|
+
inserts_obj_hash = {}
|
|
247
|
+
inserts_elements_map.each do |element,keypairs|
|
|
248
|
+
key,obj_pairs = keypairs[0],keypairs[1]
|
|
249
|
+
next unless (key and obj_pairs)
|
|
250
|
+
inserts_obj_hash[key] = Set.new(obj_pairs)
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
deletes_obj_hash = {}
|
|
254
|
+
deletes_elements_map.each do |element,keypairs|
|
|
255
|
+
key,obj_pairs = keypairs[0],keypairs[1]
|
|
256
|
+
next unless (key and obj_pairs)
|
|
257
|
+
deletes_obj_hash[key] = Set.new(obj_pairs)
|
|
258
|
+
end
|
|
259
|
+
# modified attributes
|
|
260
|
+
inserts = {}
|
|
261
|
+
deletes = {}
|
|
262
|
+
|
|
263
|
+
inserts_obj_hash.each do |key, obj_set|
|
|
264
|
+
deletes_pairs = nil
|
|
265
|
+
inserts_pairs = nil
|
|
266
|
+
if deletes_obj_hash.has_key?(key)
|
|
267
|
+
deletes_pairs = deletes_obj_hash[key].dup.subtract(obj_set).to_a
|
|
268
|
+
inserts_pairs = obj_set.dup.subtract(deletes_obj_hash[key]).to_a
|
|
269
|
+
# remove the key from the deletes set - we already processed it
|
|
270
|
+
deletes_obj_hash.delete(key)
|
|
271
|
+
else
|
|
272
|
+
# if object is not in the deletes set - then, it's all inserts
|
|
273
|
+
inserts_pairs = obj_set.to_a
|
|
274
|
+
end
|
|
275
|
+
# split resulting pairs
|
|
276
|
+
if inserts_pairs and inserts_pairs.size > 0
|
|
277
|
+
inserts[key] = split_obj_pairs(inserts_pairs)
|
|
278
|
+
end
|
|
279
|
+
if deletes_pairs and deletes_pairs.size > 0
|
|
280
|
+
deletes[key] = split_obj_pairs(deletes_pairs)
|
|
248
281
|
end
|
|
249
|
-
diff
|
|
250
|
-
else
|
|
251
|
-
res
|
|
252
282
|
end
|
|
283
|
+
# after we analyzed the inserts__obj_hash
|
|
284
|
+
# => deletes_obj_hash should contain only the unmatched deletes
|
|
285
|
+
deletes_obj_hash.each do |key, obj_set|
|
|
286
|
+
if obj_set.size > 0
|
|
287
|
+
deletes[key] = split_obj_pairs(obj_set.to_a)
|
|
288
|
+
end
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
[inserts, deletes]
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
def update_elements(dockey, inserts_elements_map, deletes_elements_map)
|
|
295
|
+
indices_to_cleanup = Set.new
|
|
296
|
+
@@db.pipelined do
|
|
297
|
+
collected_adds = {}
|
|
298
|
+
collected_rems = {}
|
|
299
|
+
|
|
300
|
+
inserts_elements_map.each do |element,keypairs|
|
|
301
|
+
key = keypairs[0]
|
|
302
|
+
next if not key or not element or element.size == 0
|
|
303
|
+
|
|
304
|
+
obj_bucket_index = _create_obj_index(key)
|
|
305
|
+
bucket_name = "#{dockey}:#{obj_bucket_index}"
|
|
306
|
+
_add_bucket_index(dockey, obj_bucket_index)
|
|
307
|
+
|
|
308
|
+
collected_adds[bucket_name] ||= []
|
|
309
|
+
collected_adds[bucket_name] << element
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
deletes_elements_map.each do |element,keypairs|
|
|
313
|
+
key = keypairs[0]
|
|
314
|
+
next if not key or not element or element.size == 0
|
|
315
|
+
|
|
316
|
+
obj_bucket_index = _create_obj_index(key)
|
|
317
|
+
bucket_name = "#{dockey}:#{obj_bucket_index}"
|
|
318
|
+
indices_to_cleanup << bucket_name
|
|
319
|
+
|
|
320
|
+
collected_rems[bucket_name] ||= []
|
|
321
|
+
collected_rems[bucket_name] << element
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
# now, perform SREM first, then SADD
|
|
325
|
+
collected_rems.each do |bucket, bucket_data|
|
|
326
|
+
@@db.srem(bucket, bucket_data)
|
|
327
|
+
end
|
|
328
|
+
collected_adds.each do |bucket,bucket_data|
|
|
329
|
+
@@db.sadd(bucket, bucket_data)
|
|
330
|
+
end
|
|
331
|
+
end
|
|
332
|
+
# now, cleanup buckets if necessary
|
|
333
|
+
_cleanup_buckets(dockey, indices_to_cleanup.to_a)
|
|
253
334
|
end
|
|
254
335
|
|
|
255
336
|
# Deletes all keys matching a given mask
|
|
@@ -367,7 +448,7 @@ module Rhoconnect
|
|
|
367
448
|
data.each do |key,hash_value|
|
|
368
449
|
unique_record_key = setelement(current_score,assoc_key, key)
|
|
369
450
|
Store.db.zadd(dockey, current_score, unique_record_key)
|
|
370
|
-
|
|
451
|
+
Store.put_data("#{dockey}:#{unique_record_key}",{key => hash_value})
|
|
371
452
|
end
|
|
372
453
|
true
|
|
373
454
|
end
|
|
@@ -403,6 +484,62 @@ module Rhoconnect
|
|
|
403
484
|
Store.db.zremrangebyrank(dockey, 0, -1)
|
|
404
485
|
end
|
|
405
486
|
|
|
487
|
+
# these methods should be used for transactional, multi-source CUD queue requests
|
|
488
|
+
def put_multi_zdata(dockey,assoc_key,sources=[],data={},append=false)
|
|
489
|
+
return true unless (dockey and assoc_key and sources and data)
|
|
490
|
+
flush_multi_zdata(dockey) unless append
|
|
491
|
+
current_score = 0
|
|
492
|
+
current_score_data = Store.db.zrevrange(dockey,0,0,:with_scores => true)
|
|
493
|
+
current_score = current_score_data[-1][1].to_i if current_score_data and current_score_data[-1]
|
|
494
|
+
current_score += 1
|
|
495
|
+
Store.put_data("#{dockey}:#{current_score.to_i}:#{assoc_key}:sources", sources)
|
|
496
|
+
data.each do |source_key,source_hashes|
|
|
497
|
+
source_hashes.each do |operation,obj_hashes|
|
|
498
|
+
unique_zrecord_key = setelement("#{current_score.to_i},#{assoc_key}",source_key,operation)
|
|
499
|
+
Store.db.zadd(dockey, current_score.to_i, unique_zrecord_key)
|
|
500
|
+
Store.put_data("#{dockey}:#{unique_zrecord_key}", obj_hashes)
|
|
501
|
+
end
|
|
502
|
+
end
|
|
503
|
+
true
|
|
504
|
+
end
|
|
505
|
+
|
|
506
|
+
def get_multi_zdata(dockey)
|
|
507
|
+
data = Store.db.zrange(dockey, 0, -1)
|
|
508
|
+
ret = []
|
|
509
|
+
sources = []
|
|
510
|
+
keys = []
|
|
511
|
+
unless data.nil?
|
|
512
|
+
scores = []
|
|
513
|
+
data.each do |zsetkey|
|
|
514
|
+
scored_assoc_key,source_key,operation = getelement(zsetkey)
|
|
515
|
+
score,assoc_key = scored_assoc_key.split(',')
|
|
516
|
+
obj_hash = Store.get_data "#{dockey}:#{zsetkey}"
|
|
517
|
+
if scores[-1] != score.to_i
|
|
518
|
+
sources << Store.get_data("#{dockey}:#{score}:#{assoc_key}:sources", Array)
|
|
519
|
+
ret << {source_key => {operation => obj_hash}}
|
|
520
|
+
scores << score.to_i
|
|
521
|
+
keys << assoc_key
|
|
522
|
+
else
|
|
523
|
+
ret[-1][source_key] ||= {}
|
|
524
|
+
ret[-1][source_key].merge!({operation => obj_hash})
|
|
525
|
+
end
|
|
526
|
+
end
|
|
527
|
+
end
|
|
528
|
+
[ret, sources, keys]
|
|
529
|
+
end
|
|
530
|
+
|
|
531
|
+
# Deletes all keys and their hashes from the Redis DB
|
|
532
|
+
def flush_multi_zdata(dockey)
|
|
533
|
+
data = Store.db.zrange(dockey, 0, -1)
|
|
534
|
+
data.each do |zsetkey|
|
|
535
|
+
scored_assoc_key,source_key,operation = getelement(zsetkey)
|
|
536
|
+
score,assoc_key = scored_assoc_key.split(',')
|
|
537
|
+
_delete_doc("#{dockey}:#{zsetkey}")
|
|
538
|
+
_delete_doc("#{dockey}:#{score}:#{assoc_key}:sources")
|
|
539
|
+
end
|
|
540
|
+
Store.db.zremrangebyrank(dockey, 0, -1)
|
|
541
|
+
end
|
|
542
|
+
|
|
406
543
|
def exists?(key)
|
|
407
544
|
@@db.exists(key) || @@db.exists("#{key}:indices")
|
|
408
545
|
end
|
|
@@ -411,20 +548,46 @@ module Rhoconnect
|
|
|
411
548
|
alias_method :set_data, :put_data
|
|
412
549
|
|
|
413
550
|
private
|
|
551
|
+
if RUBY_VERSION =~ /1.9/
|
|
414
552
|
def _get_redis(server=nil)
|
|
415
553
|
url = ENV[REDIS_URL] || ENV[REDISTOGO_URL] || nil
|
|
416
554
|
if url
|
|
417
|
-
|
|
555
|
+
ConnectionPool::Wrapper.new(:size => Rhoconnect.connection_pool_size,
|
|
556
|
+
:timeout => Rhoconnect.connection_pool_timeout) do
|
|
557
|
+
Redis.connect(:url => url, :timeout => Rhoconnect.redis_timeout, :thread_safe => true)
|
|
558
|
+
end
|
|
418
559
|
elsif server and server.is_a?(String)
|
|
419
560
|
host,port,db,password = server.split(':')
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
561
|
+
ConnectionPool::Wrapper.new(:size => Rhoconnect.connection_pool_size,
|
|
562
|
+
:timeout => Rhoconnect.connection_pool_timeout) do
|
|
563
|
+
Redis.connect(:thread_safe => true, :host => host,
|
|
564
|
+
:port => port, :db => db, :password => password, :timeout => Rhoconnect.redis_timeout)
|
|
565
|
+
end
|
|
566
|
+
elsif server and (server.is_a?(Redis) or server.is_a?(ConnectionPool::Wrapper))
|
|
423
567
|
server
|
|
424
568
|
else
|
|
425
|
-
|
|
569
|
+
ConnectionPool::Wrapper.new(:size => 5, :timeout => 30) do
|
|
570
|
+
Redis.connect(:timeout => 30, :thread_safe => true)
|
|
571
|
+
end
|
|
426
572
|
end
|
|
427
573
|
end
|
|
574
|
+
else # Ruby 1.8 does not support Connnection Pools
|
|
575
|
+
def _get_redis(server=nil)
|
|
576
|
+
url = ENV[REDIS_URL] || ENV[REDISTOGO_URL] || nil
|
|
577
|
+
if url
|
|
578
|
+
Redis.connect(:url => url, :timeout => Rhoconnect.redis_timeout, :thread_safe => true)
|
|
579
|
+
elsif server and server.is_a?(String)
|
|
580
|
+
host,port,db,password = server.split(':')
|
|
581
|
+
Redis.connect(:thread_safe => true, :host => host,
|
|
582
|
+
:port => port, :db => db, :password => password, :timeout => Rhoconnect.redis_timeout)
|
|
583
|
+
elsif server and (server.is_a?(Redis) or server.is_a?(ConnectionPool::Wrapper))
|
|
584
|
+
server
|
|
585
|
+
else
|
|
586
|
+
Redis.connect(:timeout => 30, :thread_safe => true)
|
|
587
|
+
end
|
|
588
|
+
end
|
|
589
|
+
end # end of if RUBY_VERSION
|
|
590
|
+
|
|
428
591
|
|
|
429
592
|
def _lock_key(dockey)
|
|
430
593
|
"lock:#{dockey}"
|
|
@@ -476,57 +639,142 @@ module Rhoconnect
|
|
|
476
639
|
@@db.hvals("#{dockey}:indices")
|
|
477
640
|
end
|
|
478
641
|
|
|
479
|
-
def _cleanup_buckets(dockey,
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
end if keys
|
|
642
|
+
def _cleanup_buckets(dockey, indices_to_cleanup)
|
|
643
|
+
indices_to_cleanup.each do |index|
|
|
644
|
+
bucket_name = "#{dockey}:#{index}"
|
|
645
|
+
_remove_bucket_index(dockey, index) unless @@db.exists(bucket_name)
|
|
646
|
+
end if indices_to_cleanup
|
|
485
647
|
end
|
|
486
648
|
|
|
487
|
-
def
|
|
488
|
-
return if
|
|
649
|
+
def _put_objects(dockey, data={})
|
|
650
|
+
return if data.empty? or not dockey
|
|
489
651
|
|
|
490
|
-
|
|
491
|
-
bucket_name = "#{dockey}:#{obj_bucket_index}"
|
|
492
|
-
_add_bucket_index(dockey, obj_bucket_index)
|
|
652
|
+
collected_adds = {}
|
|
493
653
|
@@db.pipelined do
|
|
494
|
-
|
|
495
|
-
unless
|
|
496
|
-
|
|
497
|
-
|
|
654
|
+
data.each do |key,obj|
|
|
655
|
+
raise ArgumentError, "Invalid value object: #{obj.inspect}. Hash is expected." unless obj.is_a?(Hash)
|
|
656
|
+
next if obj.empty? or not key
|
|
657
|
+
|
|
658
|
+
obj_bucket_index = _create_obj_index(key)
|
|
659
|
+
bucket_name = "#{dockey}:#{obj_bucket_index}"
|
|
660
|
+
_add_bucket_index(dockey, obj_bucket_index)
|
|
661
|
+
collected_adds[bucket_name] ||= []
|
|
662
|
+
collected_adds[bucket_name] << set_obj_element(key, obj)
|
|
663
|
+
|
|
664
|
+
end
|
|
665
|
+
# all SADD operations on a bucket key
|
|
666
|
+
# are combined into one - it proves to perform faster
|
|
667
|
+
collected_adds.each do |bucket,bucket_data|
|
|
668
|
+
@@db.sadd(bucket, bucket_data)
|
|
498
669
|
end
|
|
499
670
|
end
|
|
500
671
|
end
|
|
501
672
|
|
|
502
|
-
def
|
|
503
|
-
return
|
|
673
|
+
def _delete_objects(dockey, data={})
|
|
674
|
+
return 0 if data.empty? or not dockey
|
|
504
675
|
|
|
505
|
-
|
|
506
|
-
|
|
676
|
+
deleted_object_count = 0
|
|
677
|
+
indices_to_cleanup = Set.new
|
|
678
|
+
collected_rems = {}
|
|
507
679
|
@@db.pipelined do
|
|
508
|
-
|
|
509
|
-
|
|
680
|
+
data.each do |key, obj|
|
|
681
|
+
next if obj.empty? or not key
|
|
682
|
+
obj_bucket_index = _create_obj_index(key)
|
|
683
|
+
bucket_name = "#{dockey}:#{obj_bucket_index}"
|
|
684
|
+
indices_to_cleanup << obj_bucket_index
|
|
685
|
+
|
|
686
|
+
collected_rems[bucket_name] ||= []
|
|
687
|
+
collected_rems[bucket_name] << set_obj_element(key, obj)
|
|
688
|
+
deleted_object_count += 1
|
|
689
|
+
end
|
|
690
|
+
|
|
691
|
+
# all SREM operations on a bucket
|
|
692
|
+
# are combined into one
|
|
693
|
+
collected_rems.each do |bucket,bucket_data|
|
|
694
|
+
@@db.srem(bucket, bucket_data)
|
|
510
695
|
end
|
|
511
696
|
end
|
|
512
|
-
|
|
697
|
+
_cleanup_buckets(dockey, indices_to_cleanup.to_a)
|
|
698
|
+
deleted_object_count
|
|
513
699
|
end
|
|
514
700
|
|
|
515
|
-
def
|
|
701
|
+
def _get_objects(dockey, keys)
|
|
516
702
|
return nil unless dockey
|
|
517
703
|
res = nil
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
704
|
+
keys_map = Set.new
|
|
705
|
+
buckets = Set.new
|
|
706
|
+
keys.each do |key|
|
|
707
|
+
obj_bucket_index = _create_obj_index(key)
|
|
708
|
+
bucket_name = "#{dockey}:#{obj_bucket_index}"
|
|
709
|
+
keys_map << key
|
|
710
|
+
buckets << bucket_name
|
|
711
|
+
end
|
|
712
|
+
members = @@db.pipelined do
|
|
713
|
+
buckets.to_a.each do |bucket_name|
|
|
714
|
+
@@db.smembers(bucket_name)
|
|
715
|
+
end
|
|
716
|
+
end
|
|
717
|
+
members.each do |bucket_data|
|
|
718
|
+
bucket_data.each do |element|
|
|
719
|
+
key,pairs = get_obj_key_and_pairs(element)
|
|
720
|
+
next unless keys_map.include?(key)
|
|
721
|
+
obj = split_obj_pairs(pairs)
|
|
722
|
+
next if obj.empty?
|
|
723
|
+
res ||= {}
|
|
724
|
+
res[key] = obj
|
|
725
|
+
end if bucket_data
|
|
527
726
|
end if members
|
|
528
727
|
res
|
|
529
728
|
end
|
|
729
|
+
|
|
730
|
+
# operations on object elements
|
|
731
|
+
def get_obj_element(elem)
|
|
732
|
+
key,pairs = get_obj_key_and_pairs(elem)
|
|
733
|
+
return unless (key and pairs)
|
|
734
|
+
[key,split_obj_pairs(pairs)]
|
|
735
|
+
end
|
|
736
|
+
def get_obj_key_and_pairs(elem)
|
|
737
|
+
pairs = elem.split(":^rho&:")
|
|
738
|
+
return unless pairs
|
|
739
|
+
[pairs[0], pairs[1..-1]]
|
|
740
|
+
end
|
|
741
|
+
def split_obj_pairs(pairs)
|
|
742
|
+
obj = {}
|
|
743
|
+
pairs.each do |pair|
|
|
744
|
+
attrib,value = pair.split(':',2)
|
|
745
|
+
obj[attrib] = value
|
|
746
|
+
end
|
|
747
|
+
obj
|
|
748
|
+
end
|
|
749
|
+
|
|
750
|
+
# Set Obj Element MUST ensure the order of attribs
|
|
751
|
+
# In 1.8.7 Hash keys are not-sorted - therefore
|
|
752
|
+
# to ensure same order - we sort them before storing
|
|
753
|
+
if RUBY_VERSION =~ /1.8/
|
|
754
|
+
def set_obj_element(key, obj)
|
|
755
|
+
return unless (key and key.size > 0 and obj and obj.size > 0)
|
|
756
|
+
elem = "#{key}"
|
|
757
|
+
obj.sort.each do |attrib, value|
|
|
758
|
+
unless _is_reserved?(attrib,value)
|
|
759
|
+
elem += ":^rho&:#{attrib}:#{value}"
|
|
760
|
+
end
|
|
761
|
+
end
|
|
762
|
+
elem
|
|
763
|
+
end
|
|
764
|
+
# in Ruby 1.9.x Hash keys are sorted (always in the same order), so
|
|
765
|
+
# we do not need to do redundant sorting
|
|
766
|
+
else
|
|
767
|
+
def set_obj_element(key, obj)
|
|
768
|
+
return unless (key and key.size > 0 and obj and obj.size > 0)
|
|
769
|
+
elem = "#{key}"
|
|
770
|
+
obj.each do |attrib, value|
|
|
771
|
+
unless _is_reserved?(attrib,value)
|
|
772
|
+
elem += ":^rho&:#{attrib}:#{value}"
|
|
773
|
+
end
|
|
774
|
+
end
|
|
775
|
+
elem
|
|
776
|
+
end
|
|
777
|
+
end # if Ruby 1.8
|
|
530
778
|
end
|
|
531
779
|
end
|
|
532
780
|
end
|