rhoconnect 4.0.2 → 4.0.3
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 +8 -8
- data/CHANGELOG.md +4 -0
- data/Gemfile.lock +25 -25
- data/bench/benchapp/tmp/pids/passenger.9292.pid.lock +0 -0
- data/bench/benchapp/tmp/restart.txt +0 -0
- data/bench/blobapp/settings/license.key.bak +2 -0
- data/bench/blobapp/tmp/restart.txt +0 -0
- data/bench/lib/testdata/1-data.txt +0 -0
- data/bench/lib/testdata/10-data.txt +0 -0
- data/bench/lib/testdata/2-data.txt +0 -0
- data/bench/lib/testdata/250-data.txt +0 -0
- data/bench/lib/testdata/5-blob_data.txt +0 -0
- data/bench/lib/testdata/5-data.txt +0 -0
- data/bench/lib/testdata/50-data.txt +0 -0
- data/bench/lib/testdata/500-data.txt +0 -0
- data/doc/protocol.html +1993 -0
- data/lib/rhoconnect/handler/changes/engine.rb +79 -69
- data/lib/rhoconnect/store.rb +124 -123
- data/lib/rhoconnect/version.rb +1 -1
- data/spec/coverage/rcov/assets/0.2.3/jquery-1.3.2.min.js +19 -0
- data/spec/coverage/rcov/assets/0.2.3/jquery.tablesorter.min.js +15 -0
- data/spec/coverage/rcov/assets/0.2.3/print.css +12 -0
- data/spec/coverage/rcov/assets/0.2.3/rcov.js +42 -0
- data/spec/coverage/rcov/assets/0.2.3/screen.css +270 -0
- data/spec/coverage/rcov/index.html +88 -0
- data/spec/source_sync_spec.rb +27 -4
- metadata +573 -548
|
@@ -65,11 +65,9 @@ module Rhoconnect
|
|
|
65
65
|
end
|
|
66
66
|
|
|
67
67
|
def run_cud
|
|
68
|
-
return if auth_method('login') == false
|
|
69
68
|
operations.each do |op|
|
|
70
69
|
send op.to_sym
|
|
71
70
|
end
|
|
72
|
-
auth_method('logoff')
|
|
73
71
|
end
|
|
74
72
|
|
|
75
73
|
# CUD Operations
|
|
@@ -145,88 +143,100 @@ module Rhoconnect
|
|
|
145
143
|
|
|
146
144
|
# load all clients involved in the current queue
|
|
147
145
|
processed_clients = {}
|
|
148
|
-
|
|
146
|
+
user_sorted_data = {}
|
|
147
|
+
client_ids.each_with_index do |client_id, index|
|
|
149
148
|
processed_clients[client_id] = Client.load(client_id,{:source_name => @source.name}) unless processed_clients[client_id]
|
|
149
|
+
client = processed_clients[client_id]
|
|
150
|
+
user_sorted_data[client.user_id] ||= []
|
|
151
|
+
# sort by user (so that login/logoff is called exactly once per operation)
|
|
152
|
+
user_sorted_data[client.user_id] << index
|
|
150
153
|
end
|
|
151
|
-
|
|
154
|
+
|
|
152
155
|
errors,links,deletes,creates,dels = {},{},{},{},{}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
+
user_sorted_data.each do |user_id, user_entries|
|
|
157
|
+
# call login
|
|
158
|
+
# Call on source adapter to process individual object
|
|
159
|
+
# NOTE: call should be made from the correct model instance
|
|
160
|
+
model.source = Source.load(@source.name,
|
|
161
|
+
{:user_id => user_id,:app_id => APP_NAME})
|
|
162
|
+
next if auth_method('login') == false
|
|
163
|
+
user_entries.each do |index|
|
|
164
|
+
client_operation_data = operation_data[index]
|
|
165
|
+
client_id = client_ids[index]
|
|
166
|
+
client = processed_clients[client_id]
|
|
156
167
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
168
|
+
# for now - each client operation data can have only one entry (single source CUD)
|
|
169
|
+
# TODO: should be fixed for multi-source CUD
|
|
170
|
+
source_id = client_operation_data[0][0]
|
|
171
|
+
source_operation_data = client_operation_data[0][1]
|
|
172
|
+
current_invalid_meta = invalid_meta[index] || {}
|
|
173
|
+
current_invalid_source_meta = current_invalid_meta[source_id] || {}
|
|
174
|
+
record_index = 0
|
|
175
|
+
source_operation_data.each do |source_entry|
|
|
176
|
+
begin
|
|
177
|
+
key = source_entry[0]
|
|
178
|
+
value = source_entry[1]
|
|
179
|
+
continue_loop = true
|
|
180
|
+
modified_recs = [{:client_id => client_id, :key => key, :value => value }]
|
|
181
|
+
record_invalid_meta = current_invalid_source_meta[record_index] || {}
|
|
182
|
+
# remove processed entries
|
|
183
|
+
source_operation_data = source_operation_data.drop(1)
|
|
184
|
+
record_index += 1
|
|
174
185
|
|
|
175
|
-
|
|
176
|
-
|
|
186
|
+
# skip the rec - if it is a duplicate of some other record
|
|
187
|
+
next if record_invalid_meta[:duplicate_of]
|
|
177
188
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
189
|
+
# prepare duplicate docs
|
|
190
|
+
duplicates = record_invalid_meta[:duplicates] || {}
|
|
191
|
+
duplicates.each do |duplicate|
|
|
192
|
+
modified_recs << duplicate
|
|
193
|
+
end
|
|
183
194
|
|
|
184
|
-
|
|
185
|
-
|
|
195
|
+
# raise conflict error if record is marked with one
|
|
196
|
+
raise Rhoconnect::Model::ObjectConflictErrorException.new(record_invalid_meta[:error]) if record_invalid_meta[:error]
|
|
186
197
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
+
case operation
|
|
199
|
+
when 'create'
|
|
200
|
+
_process_create(modified_recs,key,value)
|
|
201
|
+
when 'update'
|
|
202
|
+
_process_update(modified_recs,key,value)
|
|
203
|
+
when 'delete'
|
|
204
|
+
_process_delete(modified_recs,key,value)
|
|
205
|
+
end
|
|
206
|
+
rescue Exception => e
|
|
207
|
+
log "Model raised #{operation} exception: #{e}"
|
|
208
|
+
log e.backtrace.join("\n")
|
|
209
|
+
continue_loop = false
|
|
210
|
+
modified_recs.each do |modified_rec|
|
|
211
|
+
modified_rec[:errors] ||= {}
|
|
212
|
+
modified_rec[:errors][modified_rec[:key]] = modified_rec[:value]
|
|
213
|
+
modified_rec[:errors]["#{modified_rec[:key]}-error"] = {'message'=>e.message}
|
|
214
|
+
end
|
|
198
215
|
end
|
|
199
|
-
rescue Exception => e
|
|
200
|
-
log "Model raised #{operation} exception: #{e}"
|
|
201
|
-
log e.backtrace.join("\n")
|
|
202
|
-
continue_loop = false
|
|
203
|
-
modified_recs.each do |modified_rec|
|
|
204
|
-
modified_rec[:errors] ||= {}
|
|
205
|
-
modified_rec[:errors][modified_rec[:key]] = modified_rec[:value]
|
|
206
|
-
modified_rec[:errors]["#{modified_rec[:key]}-error"] = {'message'=>e.message}
|
|
207
|
-
end
|
|
208
|
-
end
|
|
209
216
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
217
|
+
{ :errors => errors,
|
|
218
|
+
:links => links,
|
|
219
|
+
:deletes => deletes,
|
|
220
|
+
:creates => creates,
|
|
221
|
+
:dels => dels }.each do |doc_name, doc|
|
|
222
|
+
modified_recs.each do |modified_rec|
|
|
223
|
+
doc[modified_rec[:client_id]] ||= {}
|
|
224
|
+
next unless modified_rec[doc_name]
|
|
225
|
+
doc[modified_rec[:client_id]].merge!(modified_rec[doc_name])
|
|
226
|
+
end
|
|
219
227
|
end
|
|
228
|
+
break unless continue_loop
|
|
220
229
|
end
|
|
221
|
-
break unless continue_loop
|
|
222
|
-
end
|
|
223
230
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
231
|
+
# Record rest of queue (if something in the middle failed)
|
|
232
|
+
if not source_operation_data.empty?
|
|
233
|
+
@source.push_queue(queue_name,client_id,[[source_id, source_operation_data]],true)
|
|
234
|
+
end
|
|
227
235
|
end
|
|
236
|
+
# call logoff
|
|
237
|
+
auth_method('logoff')
|
|
228
238
|
end
|
|
229
|
-
|
|
239
|
+
|
|
230
240
|
{ "delete_page" => deletes,
|
|
231
241
|
"#{operation}_links" => links,
|
|
232
242
|
"#{operation}_errors" => errors }.each do |doctype,client_docs|
|
data/lib/rhoconnect/store.rb
CHANGED
|
@@ -3,12 +3,12 @@ require 'set'
|
|
|
3
3
|
require 'connection_pool'
|
|
4
4
|
|
|
5
5
|
module Rhoconnect
|
|
6
|
-
|
|
6
|
+
|
|
7
7
|
class StoreLockException < RuntimeError; end
|
|
8
8
|
|
|
9
9
|
class Store
|
|
10
10
|
@@dbs = nil
|
|
11
|
-
|
|
11
|
+
|
|
12
12
|
class << self
|
|
13
13
|
def nullify
|
|
14
14
|
@@dbs = nil
|
|
@@ -60,15 +60,15 @@ module Rhoconnect
|
|
|
60
60
|
end
|
|
61
61
|
end
|
|
62
62
|
alias_method :flash_data, :flush_data
|
|
63
|
-
|
|
63
|
+
|
|
64
64
|
def doc_type(dockey)
|
|
65
65
|
get_store(0).db.type(dockey) if dockey
|
|
66
66
|
end
|
|
67
|
-
|
|
67
|
+
|
|
68
68
|
def set_db_doc(dockey, data, append=false)
|
|
69
69
|
get_store(0).set_db_doc(dockey, data, append)
|
|
70
70
|
end
|
|
71
|
-
|
|
71
|
+
|
|
72
72
|
def get_db_doc(dockey)
|
|
73
73
|
doc = ""
|
|
74
74
|
@@dbs.each do |store|
|
|
@@ -83,11 +83,11 @@ module Rhoconnect
|
|
|
83
83
|
def keys(pattern)
|
|
84
84
|
get_store(0).keys(pattern)
|
|
85
85
|
end
|
|
86
|
-
|
|
86
|
+
|
|
87
87
|
def put_object(dockey, key, data={})
|
|
88
88
|
get_store(0).put_object(dockey, key, data)
|
|
89
89
|
end
|
|
90
|
-
|
|
90
|
+
|
|
91
91
|
# Adds set with given data, replaces existing set
|
|
92
92
|
# if it exists or appends data to the existing set
|
|
93
93
|
# if append flag set to true
|
|
@@ -99,32 +99,32 @@ module Rhoconnect
|
|
|
99
99
|
def put_tmp_data(dockey,data={},append=false)
|
|
100
100
|
get_store(0).put_tmp_data(dockey, data, append)
|
|
101
101
|
end
|
|
102
|
-
|
|
102
|
+
|
|
103
103
|
def put_list(dockey, data=[], append=false)
|
|
104
104
|
get_store(0).put_list(dockey, data, append)
|
|
105
105
|
end
|
|
106
|
-
|
|
106
|
+
|
|
107
107
|
# updates objects for a given doctype, source, user
|
|
108
108
|
# create new objects if necessary
|
|
109
109
|
def update_objects(dockey, data={})
|
|
110
110
|
get_store(0).update_objects(dockey, data)
|
|
111
111
|
end
|
|
112
|
-
|
|
112
|
+
|
|
113
113
|
# Removes objects from a given doctype,source,user
|
|
114
114
|
def delete_objects(dockey,data=[])
|
|
115
115
|
get_store(0).delete_objects(dockey, data)
|
|
116
116
|
end
|
|
117
|
-
|
|
117
|
+
|
|
118
118
|
# Deletes data from a given doctype,source,user
|
|
119
119
|
def delete_data(dockey,data={})
|
|
120
120
|
get_store(0).delete_data(dockey, data)
|
|
121
121
|
end
|
|
122
|
-
|
|
122
|
+
|
|
123
123
|
# Adds a simple key/value pair
|
|
124
124
|
def put_value(dockey,value)
|
|
125
125
|
get_store(0).put_value(dockey, value)
|
|
126
126
|
end
|
|
127
|
-
|
|
127
|
+
|
|
128
128
|
# Retrieves value for a given key
|
|
129
129
|
def get_value(dockey)
|
|
130
130
|
get_store(0).get_value(dockey)
|
|
@@ -133,32 +133,32 @@ module Rhoconnect
|
|
|
133
133
|
def delete_value(dockey)
|
|
134
134
|
get_store(0).delete_value(dockey)
|
|
135
135
|
end
|
|
136
|
-
|
|
136
|
+
|
|
137
137
|
def incr(dockey)
|
|
138
138
|
get_store(0).incr(dockey)
|
|
139
139
|
end
|
|
140
|
-
|
|
140
|
+
|
|
141
141
|
def decr(dockey)
|
|
142
142
|
get_store(0).decr(dockey)
|
|
143
143
|
end
|
|
144
|
-
|
|
144
|
+
|
|
145
145
|
def update_count(dockey, count)
|
|
146
146
|
get_store(0).update_count(dockey, count)
|
|
147
147
|
end
|
|
148
|
-
|
|
148
|
+
|
|
149
149
|
def get_object(dockey, key)
|
|
150
150
|
get_store(0).get_object(dockey, key)
|
|
151
151
|
end
|
|
152
|
-
|
|
152
|
+
|
|
153
153
|
def get_objects(dockey, keys)
|
|
154
154
|
get_store(0).get_objects(dockey, keys)
|
|
155
155
|
end
|
|
156
|
-
|
|
156
|
+
|
|
157
157
|
# Retrieves set for given dockey,source,user
|
|
158
158
|
def get_data(dockey,type=Hash)
|
|
159
159
|
get_store(0).get_data(dockey, type)
|
|
160
160
|
end
|
|
161
|
-
|
|
161
|
+
|
|
162
162
|
def get_list(dockey)
|
|
163
163
|
get_store(0).get_list(dockey)
|
|
164
164
|
end
|
|
@@ -187,7 +187,7 @@ module Rhoconnect
|
|
|
187
187
|
def zrange(dockey, start, stop)
|
|
188
188
|
get_store(0).zrange(dockey, start, stop)
|
|
189
189
|
end
|
|
190
|
-
|
|
190
|
+
|
|
191
191
|
# Retrieves diff data hash between two sets
|
|
192
192
|
# each entry is in the form of DIFF_OBJ_ELEMENT => [OBJ_KEY, OBJ_DATA_PAIRS]
|
|
193
193
|
def get_diff_data(src_dockey,dst_dockey,p_size=nil)
|
|
@@ -202,33 +202,33 @@ module Rhoconnect
|
|
|
202
202
|
def get_diff_data_bruteforce(src_dockey,dst_dockey,p_size=nil)
|
|
203
203
|
get_store(0).get_diff_data_bruteforce(src_dockey, dst_dockey, p_size)
|
|
204
204
|
end
|
|
205
|
-
|
|
205
|
+
|
|
206
206
|
def get_inserts_deletes(inserts_elements_map, deletes_elements_map)
|
|
207
207
|
get_store(0).get_inserts_deletes(inserts_elements_map, deletes_elements_map)
|
|
208
208
|
end
|
|
209
|
-
|
|
209
|
+
|
|
210
210
|
def update_elements(dockey, inserts_elements_map, deletes_elements_map)
|
|
211
211
|
get_store(0).update_elements(dockey, inserts_elements_map, deletes_elements_map)
|
|
212
212
|
end
|
|
213
|
-
|
|
213
|
+
|
|
214
214
|
# Lock a given key and release when provided block is finished
|
|
215
215
|
def lock(dockey,timeout=0,raise_on_expire=false, &block)
|
|
216
216
|
get_store(0).lock(dockey, timeout, raise_on_expire, &block)
|
|
217
217
|
end
|
|
218
|
-
|
|
218
|
+
|
|
219
219
|
def get_lock(dockey,timeout=0,raise_on_expire=false)
|
|
220
220
|
get_store(0).get_lock(dockey, timeout, raise_on_expire)
|
|
221
221
|
end
|
|
222
|
-
|
|
222
|
+
|
|
223
223
|
def release_lock(dockey,lock,raise_on_expire=false)
|
|
224
224
|
get_store(0).release_lock(dockey, lock, raise_on_expire)
|
|
225
225
|
end
|
|
226
|
-
|
|
226
|
+
|
|
227
227
|
# Create a copy of srckey in dstkey
|
|
228
228
|
def clone(srckey,dstkey)
|
|
229
229
|
get_store(0).clone(srckey, dstkey)
|
|
230
230
|
end
|
|
231
|
-
|
|
231
|
+
|
|
232
232
|
# Rename srckey to dstkey
|
|
233
233
|
def rename(srckey,dstkey)
|
|
234
234
|
get_store(0).rename(srckey, dstkey)
|
|
@@ -238,38 +238,38 @@ module Rhoconnect
|
|
|
238
238
|
def rename_tmp_data(srckey,dstkey)
|
|
239
239
|
get_store(0).rename_tmp_data(srckey, dstkey)
|
|
240
240
|
end
|
|
241
|
-
|
|
242
|
-
|
|
241
|
+
|
|
242
|
+
|
|
243
243
|
def put_zdata(dockey,assoc_key,data=[],append=false)
|
|
244
244
|
get_store(0).put_zdata(dockey, assoc_key, data, append)
|
|
245
245
|
end
|
|
246
|
-
|
|
246
|
+
|
|
247
247
|
# Retrieves set for given dockey,associated key (client_id), obj_hashes
|
|
248
248
|
def get_zdata(dockey)
|
|
249
249
|
get_store(0).get_zdata(dockey)
|
|
250
250
|
end
|
|
251
|
-
|
|
251
|
+
|
|
252
252
|
# Deletes all keys and their hashes from the Redis DB
|
|
253
253
|
def flush_zdata(dockey)
|
|
254
254
|
get_store(0).flush_zdata(dockey)
|
|
255
255
|
end
|
|
256
|
-
|
|
256
|
+
|
|
257
257
|
def exists?(key)
|
|
258
258
|
get_store(0).exists?(key)
|
|
259
259
|
end
|
|
260
|
-
|
|
260
|
+
|
|
261
261
|
alias_method :set_value, :put_value
|
|
262
262
|
alias_method :set_data, :put_data
|
|
263
263
|
end
|
|
264
264
|
end
|
|
265
|
-
|
|
265
|
+
|
|
266
266
|
class RedisImpl
|
|
267
267
|
RESERVED_ATTRIB_NAMES = ["attrib_type", "id"] unless defined? RESERVED_ATTRIB_NAMES
|
|
268
268
|
@db = nil
|
|
269
|
-
|
|
269
|
+
|
|
270
270
|
def create(server=nil)
|
|
271
271
|
@db ||= _get_redis(server)
|
|
272
|
-
raise "Error connecting to Redis store." unless @db and
|
|
272
|
+
raise "Error connecting to Redis store." unless @db and
|
|
273
273
|
(@db.is_a?(Redis) or @db.is_a?(Redis::Client) or @db.is_a?(ConnectionPool::Wrapper))
|
|
274
274
|
end
|
|
275
275
|
|
|
@@ -280,19 +280,19 @@ module Rhoconnect
|
|
|
280
280
|
def flush_all
|
|
281
281
|
@db.flushdb
|
|
282
282
|
end
|
|
283
|
-
|
|
283
|
+
|
|
284
284
|
def start_transaction
|
|
285
285
|
@db.multi
|
|
286
286
|
end
|
|
287
|
-
|
|
287
|
+
|
|
288
288
|
def execute_transaction
|
|
289
289
|
@db.exec
|
|
290
290
|
end
|
|
291
|
-
|
|
291
|
+
|
|
292
292
|
def doc_type(dockey)
|
|
293
293
|
@db.type(dockey) if dockey
|
|
294
294
|
end
|
|
295
|
-
|
|
295
|
+
|
|
296
296
|
def set_db_doc(dockey, data, append=false)
|
|
297
297
|
if data.is_a?(String)
|
|
298
298
|
put_value(dockey, data)
|
|
@@ -300,7 +300,7 @@ module Rhoconnect
|
|
|
300
300
|
put_data(dockey, data, append)
|
|
301
301
|
end
|
|
302
302
|
end
|
|
303
|
-
|
|
303
|
+
|
|
304
304
|
def get_db_doc(dockey)
|
|
305
305
|
doctype = doc_type(dockey)
|
|
306
306
|
if doctype == 'string'
|
|
@@ -311,7 +311,7 @@ module Rhoconnect
|
|
|
311
311
|
get_data(dockey).to_json
|
|
312
312
|
end
|
|
313
313
|
end
|
|
314
|
-
|
|
314
|
+
|
|
315
315
|
def put_object(dockey, key, data={})
|
|
316
316
|
_put_objects(dockey, {key => data})
|
|
317
317
|
end
|
|
@@ -337,7 +337,7 @@ module Rhoconnect
|
|
|
337
337
|
end
|
|
338
338
|
true
|
|
339
339
|
end
|
|
340
|
-
|
|
340
|
+
|
|
341
341
|
def put_list(dockey, data=[], append=false, ttl=0)
|
|
342
342
|
if dockey and data
|
|
343
343
|
flush_data(dockey) unless append
|
|
@@ -350,15 +350,15 @@ module Rhoconnect
|
|
|
350
350
|
end
|
|
351
351
|
true
|
|
352
352
|
end
|
|
353
|
-
|
|
353
|
+
|
|
354
354
|
# updates objects for a given doctype, source, user
|
|
355
355
|
# create new objects if necessary
|
|
356
356
|
def update_objects(dockey, data={})
|
|
357
357
|
return 0 unless dockey and data
|
|
358
|
-
|
|
358
|
+
|
|
359
359
|
new_object_count = 0
|
|
360
360
|
objs = get_objects(dockey, data.keys) || {}
|
|
361
|
-
|
|
361
|
+
|
|
362
362
|
collected_adds = {}
|
|
363
363
|
collected_rems = {}
|
|
364
364
|
my_bucket = nil
|
|
@@ -367,7 +367,7 @@ module Rhoconnect
|
|
|
367
367
|
is_create = objs[key].nil?
|
|
368
368
|
new_object_count += 1 if is_create
|
|
369
369
|
obj_bucket = _add_bucket_index(dockey, "#{_create_obj_index(key)}")
|
|
370
|
-
|
|
370
|
+
|
|
371
371
|
# collect SREM (if object exists in DB)
|
|
372
372
|
unless is_create
|
|
373
373
|
old_element = set_obj_element(key,objs[key])
|
|
@@ -377,7 +377,7 @@ module Rhoconnect
|
|
|
377
377
|
# update the object and collect SADD
|
|
378
378
|
objs[key] ||= {}
|
|
379
379
|
objs[key].merge!(obj)
|
|
380
|
-
|
|
380
|
+
|
|
381
381
|
new_element = set_obj_element(key,objs[key])
|
|
382
382
|
collected_adds[obj_bucket] ||= []
|
|
383
383
|
collected_adds[obj_bucket] << new_element
|
|
@@ -391,22 +391,22 @@ module Rhoconnect
|
|
|
391
391
|
@db.sadd(bucket, bucket_data)
|
|
392
392
|
end
|
|
393
393
|
end
|
|
394
|
-
|
|
395
|
-
|
|
394
|
+
|
|
395
|
+
|
|
396
396
|
#data1 = @db.smembers(my_bucket)
|
|
397
397
|
#puts "data1 is #{data1.inspect}"
|
|
398
|
-
|
|
398
|
+
|
|
399
399
|
new_object_count
|
|
400
400
|
end
|
|
401
|
-
|
|
401
|
+
|
|
402
402
|
# Removes objects from a given doctype,source,user
|
|
403
403
|
def delete_objects(dockey,data=[])
|
|
404
404
|
return 0 unless dockey and data
|
|
405
|
-
|
|
405
|
+
|
|
406
406
|
objs = get_objects(dockey, data)
|
|
407
407
|
_delete_objects(dockey, objs)
|
|
408
408
|
end
|
|
409
|
-
|
|
409
|
+
|
|
410
410
|
# Deletes data from a given doctype,source,user
|
|
411
411
|
def delete_data(dockey,data={})
|
|
412
412
|
if dockey and data
|
|
@@ -414,18 +414,18 @@ module Rhoconnect
|
|
|
414
414
|
end
|
|
415
415
|
true
|
|
416
416
|
end
|
|
417
|
-
|
|
417
|
+
|
|
418
418
|
# Adds a simple key/value pair
|
|
419
419
|
def put_value(dockey,value)
|
|
420
420
|
if dockey
|
|
421
|
-
if value
|
|
421
|
+
if value
|
|
422
422
|
@db.set(dockey,value.to_s)
|
|
423
423
|
else
|
|
424
|
-
@db.del(dockey)
|
|
424
|
+
@db.del(dockey)
|
|
425
425
|
end
|
|
426
426
|
end
|
|
427
427
|
end
|
|
428
|
-
|
|
428
|
+
|
|
429
429
|
# Retrieves value for a given key
|
|
430
430
|
def get_value(dockey)
|
|
431
431
|
@db.get(dockey) if dockey
|
|
@@ -438,20 +438,20 @@ module Rhoconnect
|
|
|
438
438
|
def incr(dockey)
|
|
439
439
|
@db.incr(dockey)
|
|
440
440
|
end
|
|
441
|
-
|
|
441
|
+
|
|
442
442
|
def decr(dockey)
|
|
443
443
|
@db.decr(dockey)
|
|
444
444
|
end
|
|
445
|
-
|
|
445
|
+
|
|
446
446
|
def update_count(dockey, count)
|
|
447
447
|
@db.incrby(dockey, count)
|
|
448
448
|
end
|
|
449
|
-
|
|
449
|
+
|
|
450
450
|
def get_object(dockey, key)
|
|
451
451
|
res = _get_objects(dockey, [key])
|
|
452
452
|
(res and res.size > 0) ? res.values[0] : nil
|
|
453
453
|
end
|
|
454
|
-
|
|
454
|
+
|
|
455
455
|
def get_objects(dockey, keys)
|
|
456
456
|
_get_objects(dockey, keys)
|
|
457
457
|
end
|
|
@@ -480,7 +480,7 @@ module Rhoconnect
|
|
|
480
480
|
end
|
|
481
481
|
res
|
|
482
482
|
end
|
|
483
|
-
|
|
483
|
+
|
|
484
484
|
def get_list(dockey)
|
|
485
485
|
res = []
|
|
486
486
|
if dockey
|
|
@@ -557,7 +557,7 @@ module Rhoconnect
|
|
|
557
557
|
end
|
|
558
558
|
[inserts, deletes]
|
|
559
559
|
end
|
|
560
|
-
|
|
560
|
+
|
|
561
561
|
def get_inserts_deletes(inserts_elements_map, deletes_elements_map)
|
|
562
562
|
inserts_obj_hash = {}
|
|
563
563
|
inserts_elements_map.each do |element,keypairs|
|
|
@@ -565,7 +565,7 @@ module Rhoconnect
|
|
|
565
565
|
next unless (key and obj_pairs)
|
|
566
566
|
inserts_obj_hash[key] = Set.new(obj_pairs)
|
|
567
567
|
end
|
|
568
|
-
|
|
568
|
+
|
|
569
569
|
deletes_obj_hash = {}
|
|
570
570
|
deletes_elements_map.each do |element,keypairs|
|
|
571
571
|
key,obj_pairs = keypairs[0],keypairs[1]
|
|
@@ -575,7 +575,7 @@ module Rhoconnect
|
|
|
575
575
|
# modified attributes
|
|
576
576
|
inserts = {}
|
|
577
577
|
deletes = {}
|
|
578
|
-
|
|
578
|
+
|
|
579
579
|
inserts_obj_hash.each do |key, obj_set|
|
|
580
580
|
deletes_pairs = nil
|
|
581
581
|
inserts_pairs = nil
|
|
@@ -603,40 +603,40 @@ module Rhoconnect
|
|
|
603
603
|
deletes[key] = split_obj_pairs(obj_set.to_a)
|
|
604
604
|
end
|
|
605
605
|
end
|
|
606
|
-
|
|
607
|
-
[inserts, deletes]
|
|
606
|
+
|
|
607
|
+
[inserts, deletes]
|
|
608
608
|
end
|
|
609
|
-
|
|
609
|
+
|
|
610
610
|
def update_elements(dockey, inserts_elements_map, deletes_elements_map)
|
|
611
611
|
indices_to_cleanup = Set.new
|
|
612
612
|
@db.pipelined do
|
|
613
613
|
collected_adds = {}
|
|
614
614
|
collected_rems = {}
|
|
615
|
-
|
|
615
|
+
|
|
616
616
|
inserts_elements_map.each do |element,keypairs|
|
|
617
617
|
key = keypairs[0]
|
|
618
618
|
next if not key or not element or element.size == 0
|
|
619
|
-
|
|
619
|
+
|
|
620
620
|
obj_bucket_index = _create_obj_index(key)
|
|
621
621
|
bucket_name = "#{dockey}:#{obj_bucket_index}"
|
|
622
622
|
_add_bucket_index(dockey, obj_bucket_index)
|
|
623
|
-
|
|
623
|
+
|
|
624
624
|
collected_adds[bucket_name] ||= []
|
|
625
625
|
collected_adds[bucket_name] << element
|
|
626
626
|
end
|
|
627
|
-
|
|
627
|
+
|
|
628
628
|
deletes_elements_map.each do |element,keypairs|
|
|
629
629
|
key = keypairs[0]
|
|
630
630
|
next if not key or not element or element.size == 0
|
|
631
|
-
|
|
631
|
+
|
|
632
632
|
obj_bucket_index = _create_obj_index(key)
|
|
633
633
|
bucket_name = "#{dockey}:#{obj_bucket_index}"
|
|
634
634
|
indices_to_cleanup << bucket_name
|
|
635
|
-
|
|
635
|
+
|
|
636
636
|
collected_rems[bucket_name] ||= []
|
|
637
637
|
collected_rems[bucket_name] << element
|
|
638
638
|
end
|
|
639
|
-
|
|
639
|
+
|
|
640
640
|
# now, perform SREM first, then SADD
|
|
641
641
|
collected_rems.each do |bucket, bucket_data|
|
|
642
642
|
@db.srem(bucket, bucket_data)
|
|
@@ -644,7 +644,7 @@ module Rhoconnect
|
|
|
644
644
|
collected_adds.each do |bucket,bucket_data|
|
|
645
645
|
@db.sadd(bucket, bucket_data)
|
|
646
646
|
end
|
|
647
|
-
end
|
|
647
|
+
end
|
|
648
648
|
# now, cleanup buckets if necessary
|
|
649
649
|
_cleanup_buckets(dockey, indices_to_cleanup.to_a)
|
|
650
650
|
end
|
|
@@ -669,7 +669,7 @@ module Rhoconnect
|
|
|
669
669
|
end
|
|
670
670
|
end
|
|
671
671
|
alias_method :flash_data, :flush_data
|
|
672
|
-
|
|
672
|
+
|
|
673
673
|
# Lock a given key and release when provided block is finished
|
|
674
674
|
def lock(dockey,timeout=0,raise_on_expire=false, &block)
|
|
675
675
|
m_lock = get_lock(dockey,timeout,raise_on_expire)
|
|
@@ -677,12 +677,12 @@ module Rhoconnect
|
|
|
677
677
|
release_lock(dockey,m_lock)
|
|
678
678
|
res
|
|
679
679
|
end
|
|
680
|
-
|
|
680
|
+
|
|
681
681
|
def get_lock(dockey,timeout=0,raise_on_expire=false)
|
|
682
682
|
lock_key = _lock_key(dockey)
|
|
683
|
-
current_time = Time.now.to_i
|
|
683
|
+
current_time = Time.now.to_i
|
|
684
684
|
ts = current_time+(Rhoconnect.lock_duration || timeout)+1
|
|
685
|
-
loop do
|
|
685
|
+
loop do
|
|
686
686
|
if not @db.setnx(lock_key,ts)
|
|
687
687
|
current_lock = @db.get(lock_key)
|
|
688
688
|
# ensure lock wasn't released between the setnx and get calls
|
|
@@ -691,11 +691,11 @@ module Rhoconnect
|
|
|
691
691
|
if raise_on_expire or Rhoconnect.raise_on_expired_lock
|
|
692
692
|
if current_lock_timeout <= current_time
|
|
693
693
|
# lock expired before operation which set it up completed
|
|
694
|
-
# this process cannot continue without corrupting locked data
|
|
694
|
+
# this process cannot continue without corrupting locked data
|
|
695
695
|
raise StoreLockException, "Lock \"#{lock_key}\" expired before it was released"
|
|
696
696
|
end
|
|
697
|
-
else
|
|
698
|
-
if current_lock_timeout <= current_time and
|
|
697
|
+
else
|
|
698
|
+
if current_lock_timeout <= current_time and
|
|
699
699
|
@db.getset(lock_key,ts).to_i <= current_time
|
|
700
700
|
# previous lock expired and we replaced it with our own
|
|
701
701
|
break
|
|
@@ -713,21 +713,21 @@ module Rhoconnect
|
|
|
713
713
|
end
|
|
714
714
|
return ts
|
|
715
715
|
end
|
|
716
|
-
|
|
716
|
+
|
|
717
717
|
# Due to redis bug #140, setnx always returns true so this doesn't work
|
|
718
718
|
# def get_lock(dockey,timeout=0)
|
|
719
719
|
# lock_key = _lock_key(dockey)
|
|
720
|
-
# until @db.setnx(lock_key,1) do
|
|
721
|
-
# sleep(1)
|
|
720
|
+
# until @db.setnx(lock_key,1) do
|
|
721
|
+
# sleep(1)
|
|
722
722
|
# end
|
|
723
723
|
# @db.expire(lock_key,timeout+1)
|
|
724
724
|
# Time.now.to_i+timeout+1
|
|
725
725
|
# end
|
|
726
|
-
|
|
726
|
+
|
|
727
727
|
def release_lock(dockey,lock,raise_on_expire=false)
|
|
728
728
|
@db.del(_lock_key(dockey)) if raise_on_expire or Rhoconnect.raise_on_expired_lock or (lock >= Time.now.to_i)
|
|
729
729
|
end
|
|
730
|
-
|
|
730
|
+
|
|
731
731
|
# Create a copy of srckey in dstkey
|
|
732
732
|
def clone(srckey,dstkey)
|
|
733
733
|
buckets = _get_bucket_indices(srckey)
|
|
@@ -742,7 +742,7 @@ module Rhoconnect
|
|
|
742
742
|
@db.sdiffstore(dstkey,srckey,'')
|
|
743
743
|
end
|
|
744
744
|
end
|
|
745
|
-
|
|
745
|
+
|
|
746
746
|
# Rename temp doc srckey to persist dstkey
|
|
747
747
|
def rename_tmp_data(srckey,dstkey)
|
|
748
748
|
rename(srckey,dstkey,true)
|
|
@@ -762,18 +762,18 @@ module Rhoconnect
|
|
|
762
762
|
if make_persist
|
|
763
763
|
@db.persist("#{dstkey}:indices")
|
|
764
764
|
buckets.each do |bucket_index|
|
|
765
|
-
@db.persist("#{dstkey}:#{bucket_index}")
|
|
765
|
+
@db.persist("#{dstkey}:#{bucket_index}")
|
|
766
766
|
end
|
|
767
767
|
end
|
|
768
768
|
end
|
|
769
769
|
else
|
|
770
|
-
if @db.exists(srckey)
|
|
770
|
+
if @db.exists(srckey)
|
|
771
771
|
@db.rename(srckey,dstkey)
|
|
772
772
|
@db.persist(dstkey) if make_persist
|
|
773
773
|
end
|
|
774
774
|
end
|
|
775
775
|
end
|
|
776
|
-
|
|
776
|
+
|
|
777
777
|
def put_zdata(dockey,assoc_key,data=[],append=false)
|
|
778
778
|
return true unless (dockey and assoc_key and data)
|
|
779
779
|
flush_zdata(dockey) unless append
|
|
@@ -795,7 +795,7 @@ module Rhoconnect
|
|
|
795
795
|
end if data
|
|
796
796
|
true
|
|
797
797
|
end
|
|
798
|
-
|
|
798
|
+
|
|
799
799
|
# Retrieves set for given dockey,associated key (client_id), obj_hashes
|
|
800
800
|
def get_zdata(dockey)
|
|
801
801
|
data = @db.zrange(dockey, 0, -1)
|
|
@@ -822,7 +822,7 @@ module Rhoconnect
|
|
|
822
822
|
end if data
|
|
823
823
|
[ret, assoc_keys]
|
|
824
824
|
end
|
|
825
|
-
|
|
825
|
+
|
|
826
826
|
# Deletes all keys and their hashes from the Redis DB
|
|
827
827
|
def flush_zdata(dockey)
|
|
828
828
|
data = @db.zrange(dockey, 0, -1)
|
|
@@ -831,7 +831,7 @@ module Rhoconnect
|
|
|
831
831
|
end
|
|
832
832
|
@db.zremrangebyrank(dockey, 0, -1)
|
|
833
833
|
end
|
|
834
|
-
|
|
834
|
+
|
|
835
835
|
def exists?(key)
|
|
836
836
|
@db.exists(key) || @db.exists("#{key}:indices")
|
|
837
837
|
end
|
|
@@ -860,10 +860,10 @@ module Rhoconnect
|
|
|
860
860
|
def zrange(dockey, start, stop)
|
|
861
861
|
@db.zrange(dockey, start, stop)
|
|
862
862
|
end
|
|
863
|
-
|
|
863
|
+
|
|
864
864
|
alias_method :set_value, :put_value
|
|
865
865
|
alias_method :set_data, :put_data
|
|
866
|
-
|
|
866
|
+
|
|
867
867
|
# This method should never be accessed by anything except specs
|
|
868
868
|
def db
|
|
869
869
|
return @db
|
|
@@ -884,6 +884,7 @@ module Rhoconnect
|
|
|
884
884
|
host,port,db,password = server.split(':')
|
|
885
885
|
ConnectionPool::Wrapper.new(:size => Rhoconnect.connection_pool_size,
|
|
886
886
|
:timeout => Rhoconnect.connection_pool_timeout) do
|
|
887
|
+
host = '127.0.0.1' if host == 'localhost'
|
|
887
888
|
Redis.connect(:thread_safe => true, :host => host,
|
|
888
889
|
:port => port, :db => db, :password => password, :timeout => Rhoconnect.redis_timeout)
|
|
889
890
|
end
|
|
@@ -896,15 +897,15 @@ module Rhoconnect
|
|
|
896
897
|
end
|
|
897
898
|
end
|
|
898
899
|
end
|
|
899
|
-
|
|
900
|
+
|
|
900
901
|
def _lock_key(dockey)
|
|
901
902
|
"lock:#{dockey}"
|
|
902
903
|
end
|
|
903
|
-
|
|
904
|
+
|
|
904
905
|
def _is_reserved?(attrib,value) #:nodoc:
|
|
905
906
|
RESERVED_ATTRIB_NAMES.include? attrib
|
|
906
907
|
end
|
|
907
|
-
|
|
908
|
+
|
|
908
909
|
# operations with docs that are split into buckets
|
|
909
910
|
def _delete_doc(dockey)
|
|
910
911
|
# check if this doc has buckets
|
|
@@ -918,57 +919,57 @@ module Rhoconnect
|
|
|
918
919
|
end
|
|
919
920
|
end
|
|
920
921
|
end
|
|
921
|
-
|
|
922
|
-
# delete main doc
|
|
922
|
+
|
|
923
|
+
# delete main doc
|
|
923
924
|
@db.del(dockey)
|
|
924
925
|
end
|
|
925
|
-
|
|
926
|
+
|
|
926
927
|
# create object's bucket index
|
|
927
928
|
# using SHA1 hashing
|
|
928
929
|
def _create_obj_index(key)
|
|
929
930
|
Digest::SHA1.hexdigest(key)[0..1]
|
|
930
931
|
end
|
|
931
|
-
|
|
932
|
+
|
|
932
933
|
def _add_bucket_index(dockey, bucket_index)
|
|
933
934
|
bucket_name = "#{dockey}:#{bucket_index}"
|
|
934
935
|
@db.hsetnx("#{dockey}:indices", bucket_index, bucket_name)
|
|
935
936
|
bucket_name
|
|
936
937
|
end
|
|
937
|
-
|
|
938
|
+
|
|
938
939
|
def _remove_bucket_index(dockey, bucket_index)
|
|
939
940
|
@db.hdel("#{dockey}:indices", bucket_index)
|
|
940
941
|
end
|
|
941
|
-
|
|
942
|
+
|
|
942
943
|
def _get_bucket_indices(dockey)
|
|
943
944
|
@db.hkeys("#{dockey}:indices")
|
|
944
945
|
end
|
|
945
|
-
|
|
946
|
+
|
|
946
947
|
def _get_buckets(dockey)
|
|
947
948
|
@db.hvals("#{dockey}:indices")
|
|
948
949
|
end
|
|
949
|
-
|
|
950
|
+
|
|
950
951
|
def _cleanup_buckets(dockey, indices_to_cleanup)
|
|
951
952
|
indices_to_cleanup.each do |index|
|
|
952
953
|
bucket_name = "#{dockey}:#{index}"
|
|
953
954
|
_remove_bucket_index(dockey, index) unless @db.exists(bucket_name)
|
|
954
955
|
end if indices_to_cleanup
|
|
955
956
|
end
|
|
956
|
-
|
|
957
|
+
|
|
957
958
|
def _put_objects(dockey, data={}, ttl=0)
|
|
958
959
|
return if data.empty? or not dockey
|
|
959
|
-
|
|
960
|
+
|
|
960
961
|
collected_adds = {}
|
|
961
962
|
@db.pipelined do
|
|
962
963
|
data.each do |key,obj|
|
|
963
964
|
raise ArgumentError, "Invalid value object: #{obj.inspect}. Hash is expected." unless obj.is_a?(Hash)
|
|
964
965
|
next if obj.empty? or not key
|
|
965
|
-
|
|
966
|
+
|
|
966
967
|
obj_bucket_index = _create_obj_index(key)
|
|
967
968
|
bucket_name = "#{dockey}:#{obj_bucket_index}"
|
|
968
969
|
_add_bucket_index(dockey, obj_bucket_index)
|
|
969
970
|
collected_adds[bucket_name] ||= []
|
|
970
971
|
collected_adds[bucket_name] << set_obj_element(key, obj)
|
|
971
|
-
|
|
972
|
+
|
|
972
973
|
end
|
|
973
974
|
# all SADD operations on a bucket key
|
|
974
975
|
# are combined into one - it proves to perform faster
|
|
@@ -981,10 +982,10 @@ module Rhoconnect
|
|
|
981
982
|
@db.expire("#{dockey}:indices", ttl) if ttl > 0
|
|
982
983
|
end
|
|
983
984
|
end
|
|
984
|
-
|
|
985
|
+
|
|
985
986
|
def _delete_objects(dockey, data={})
|
|
986
987
|
return 0 if data.empty? or not dockey
|
|
987
|
-
|
|
988
|
+
|
|
988
989
|
deleted_object_count = 0
|
|
989
990
|
indices_to_cleanup = Set.new
|
|
990
991
|
collected_rems = {}
|
|
@@ -994,12 +995,12 @@ module Rhoconnect
|
|
|
994
995
|
obj_bucket_index = _create_obj_index(key)
|
|
995
996
|
bucket_name = "#{dockey}:#{obj_bucket_index}"
|
|
996
997
|
indices_to_cleanup << obj_bucket_index
|
|
997
|
-
|
|
998
|
+
|
|
998
999
|
collected_rems[bucket_name] ||= []
|
|
999
1000
|
collected_rems[bucket_name] << set_obj_element(key, obj)
|
|
1000
1001
|
deleted_object_count += 1
|
|
1001
1002
|
end
|
|
1002
|
-
|
|
1003
|
+
|
|
1003
1004
|
# all SREM operations on a bucket
|
|
1004
1005
|
# are combined into one
|
|
1005
1006
|
collected_rems.each do |bucket,bucket_data|
|
|
@@ -1009,7 +1010,7 @@ module Rhoconnect
|
|
|
1009
1010
|
_cleanup_buckets(dockey, indices_to_cleanup.to_a)
|
|
1010
1011
|
deleted_object_count
|
|
1011
1012
|
end
|
|
1012
|
-
|
|
1013
|
+
|
|
1013
1014
|
def _get_objects(dockey, keys)
|
|
1014
1015
|
return nil unless dockey
|
|
1015
1016
|
res = nil
|
|
@@ -1038,8 +1039,8 @@ module Rhoconnect
|
|
|
1038
1039
|
end if members
|
|
1039
1040
|
res
|
|
1040
1041
|
end
|
|
1041
|
-
|
|
1042
|
-
# operations on object elements
|
|
1042
|
+
|
|
1043
|
+
# operations on object elements
|
|
1043
1044
|
def get_obj_element(elem)
|
|
1044
1045
|
key,pairs = get_obj_key_and_pairs(elem)
|
|
1045
1046
|
return unless (key and pairs)
|
|
@@ -1060,7 +1061,7 @@ module Rhoconnect
|
|
|
1060
1061
|
end
|
|
1061
1062
|
|
|
1062
1063
|
# Set Obj Element MUST ensure the order of attribs
|
|
1063
|
-
# in Ruby 1.9.x Hash keys are sorted (always in the same order), so
|
|
1064
|
+
# in Ruby 1.9.x Hash keys are sorted (always in the same order), so
|
|
1064
1065
|
# we do not need to do redundant sorting
|
|
1065
1066
|
def set_obj_element(key, obj)
|
|
1066
1067
|
return unless (key and key.size > 0 and obj and obj.size > 0)
|
|
@@ -1073,4 +1074,4 @@ module Rhoconnect
|
|
|
1073
1074
|
elem
|
|
1074
1075
|
end
|
|
1075
1076
|
end
|
|
1076
|
-
end
|
|
1077
|
+
end
|