rhoconnect 3.0.6 → 3.1.0.beta1
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 +9 -0
- data/Gemfile +3 -3
- data/Gemfile.lock +38 -17
- data/Rakefile +0 -10
- data/bench/benchapp/Gemfile.lock +1 -0
- data/bench/distr_bench/distr_bench_main +94 -27
- data/bench/distr_bench/run_test_query_script.sh +22 -18
- data/bench/lib/bench/aws_utils.rb +326 -0
- data/bench/lib/bench/bench_result_processor.rb +268 -75
- data/bench/lib/bench/cli.rb +1 -0
- data/bench/lib/bench/distr_runner.rb +102 -0
- data/bench/lib/bench/utils.rb +127 -0
- data/bench/lib/bench.rb +16 -15
- data/bench/prepare_bench +3 -11
- data/bench/scripts/test_query_script.rb +6 -7
- data/bin/rhoconnect-benchmark +257 -5
- data/doc/benchmarks-running.txt +140 -0
- data/doc/client-java.txt +236 -0
- data/doc/client-objc.txt +41 -1
- data/doc/client.txt +12 -0
- data/doc/command-line.txt +12 -3
- data/doc/cud-conflicts.txt +68 -0
- data/doc/deploying.txt +1 -70
- data/doc/hosting-rhohub.txt +3 -0
- data/doc/install.txt +50 -13
- data/doc/java-plugin.txt +217 -177
- data/doc/net-plugin.txt +97 -64
- data/doc/plugin-intro.txt +4 -2
- data/doc/preparing-production.txt +63 -0
- data/doc/rhoconnect-redis-stack.txt +252 -0
- data/doc/source-adapters.txt +3 -1
- data/doc/tutorial.txt +111 -49
- data/examples/simple/dump.rdb +0 -0
- data/installer/unix-like/rho_connect_install_constants.rb +6 -5
- data/installer/unix-like/rho_connect_install_installers.rb +6 -2
- data/installer/utils/nix_install_test.rb +2 -0
- data/installer/utils/package_upload/auto-repo.rb +136 -0
- data/installer/utils/package_upload/repos.rake +6 -3
- data/installer/utils/package_upload/s3_upload.rb +11 -6
- data/installer/windows/rhosync.nsi +5 -5
- data/lib/rhoconnect/client_sync.rb +2 -2
- data/lib/rhoconnect/document.rb +12 -0
- data/lib/rhoconnect/jobs/source_job.rb +2 -2
- data/lib/rhoconnect/predefined_adapters/bench_adapter.rb +61 -0
- data/lib/rhoconnect/source.rb +5 -0
- data/lib/rhoconnect/source_adapter.rb +10 -1
- data/lib/rhoconnect/source_sync.rb +161 -88
- data/lib/rhoconnect/store.rb +48 -0
- data/lib/rhoconnect/test_methods.rb +6 -6
- data/lib/rhoconnect/version.rb +1 -1
- data/lib/rhoconnect.rb +25 -2
- data/spec/apps/rhotestapp/sources/sample_adapter.rb +29 -0
- data/spec/jobs/source_job_spec.rb +5 -5
- data/spec/source_adapter_spec.rb +10 -0
- data/spec/source_sync_spec.rb +114 -33
- data/spec/spec_helper.rb +21 -2
- data/spec/store_spec.rb +29 -0
- data/spec/support/shared_examples.rb +1 -1
- data/spec/test_methods_spec.rb +4 -4
- data/tasks/redis.rake +2 -2
- metadata +59 -59
- data/bench/benchapp/log/passenger.3000.log +0 -1
- data/bench/benchapp/log/passenger.9292.log +0 -59
- data/bench/benchapp/tmp/pids/passenger.3000.pid.lock +0 -0
- data/bench/benchapp/tmp/pids/passenger.9292.pid.lock +0 -0
- data/bench/lib/testdata/0-data.txt +0 -0
- data/bench/lib/testdata/1-data.txt +0 -0
- data/bench/lib/testdata/10-data.txt +0 -15
- data/bench/lib/testdata/2-data.txt +0 -3
- data/bench/lib/testdata/25-data.txt +0 -39
- data/bench/lib/testdata/250-data.txt +0 -353
- data/bench/lib/testdata/3-data.txt +0 -4
- data/bench/lib/testdata/50-data.txt +0 -70
- data/bench/lib/testdata/500-data.txt +0 -711
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'rest_client'
|
3
|
+
require 'uri'
|
4
|
+
|
5
|
+
module Rhoconnect
|
6
|
+
# register the adapter as pre-defined
|
7
|
+
Rhoconnect.register_predefined_source('RhoInternalBenchmarkAdapter')
|
8
|
+
|
9
|
+
class RhoInternalBenchmarkAdapter < Rhoconnect::SourceAdapter
|
10
|
+
def initialize(source)
|
11
|
+
super(source)
|
12
|
+
end
|
13
|
+
|
14
|
+
def login
|
15
|
+
true
|
16
|
+
end
|
17
|
+
|
18
|
+
def query(params=nil)
|
19
|
+
Rhoconnect::Store.lock(lock_name,1) do
|
20
|
+
@result = Rhoconnect::Store.get_data(db_name)
|
21
|
+
end
|
22
|
+
@result
|
23
|
+
end
|
24
|
+
|
25
|
+
def create(create_hash)
|
26
|
+
id = create_hash['mock_id']
|
27
|
+
Rhoconnect::Store.lock(lock_name,1) do
|
28
|
+
Rhoconnect::Store.put_data(db_name,{id=>create_hash},true) if id
|
29
|
+
end
|
30
|
+
id
|
31
|
+
end
|
32
|
+
|
33
|
+
def update(update_hash)
|
34
|
+
id = update_hash.delete('id')
|
35
|
+
return unless id
|
36
|
+
Rhoconnect::Store.lock(lock_name,1) do
|
37
|
+
data = Rhoconnect::Store.get_data(db_name)
|
38
|
+
return unless data and data[id]
|
39
|
+
update_hash.each do |attrib,value|
|
40
|
+
data[id][attrib] = value
|
41
|
+
end
|
42
|
+
Rhoconnect::Store.put_data(db_name,data)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def delete(delete_hash)
|
47
|
+
id = delete_hash.delete('id')
|
48
|
+
Rhoconnect::Store.lock(lock_name,1) do
|
49
|
+
Rhoconnect::Store.delete_data(db_name,{id=>delete_hash}) if id
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def db_name
|
54
|
+
"test_db_storage:#{@source.app_id}:#{@source.user_id}"
|
55
|
+
end
|
56
|
+
|
57
|
+
def lock_name
|
58
|
+
"lock:#{db_name}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
data/lib/rhoconnect/source.rb
CHANGED
@@ -127,6 +127,11 @@ module Rhoconnect
|
|
127
127
|
|
128
128
|
def self.load(obj_id,params)
|
129
129
|
validate_attributes(params)
|
130
|
+
|
131
|
+
# if source is pre-defined
|
132
|
+
# create it dynamically here
|
133
|
+
Rhoconnect.create_predefined_source(obj_id,params)
|
134
|
+
|
130
135
|
model_hash = @@model_data[obj_id.to_sym]
|
131
136
|
obj = new(model_hash) if model_hash
|
132
137
|
if obj
|
@@ -27,9 +27,13 @@ module Rhoconnect
|
|
27
27
|
source.name = source.name.dup if source.name.frozen?
|
28
28
|
source.name.strip!
|
29
29
|
end
|
30
|
+
# certain adapters are pre-defined and reserved
|
31
|
+
# load them and instantiate
|
32
|
+
if Rhoconnect.predefined_sources.has_key?(source.name)
|
33
|
+
adapter=(Object.const_get(source.name)).new(source)
|
34
|
+
elsif Object.const_defined?(source.name) && Object.const_get(source.name).to_s.split("::").first != 'Rhoconnect'
|
30
35
|
# fix until source adpaters are phased out, checking for Rhoconnect namespace
|
31
36
|
# so that backend models with same name as Rhoconnect models are instantiated correctly
|
32
|
-
if Object.const_defined?(source.name) && Object.const_get(source.name).to_s.split("::").first != 'Rhoconnect'
|
33
37
|
require under_score(source.name)
|
34
38
|
adapter=(Object.const_get(source.name)).new(source)
|
35
39
|
else
|
@@ -95,6 +99,11 @@ module Rhoconnect
|
|
95
99
|
Rhoconnect.expire_bulk_data(current_user.login,partition)
|
96
100
|
end
|
97
101
|
|
102
|
+
# do pre-processing before CUD operation
|
103
|
+
def validate(operation,operations_hashes,client_ids)
|
104
|
+
{}
|
105
|
+
end
|
106
|
+
|
98
107
|
def create(create_hash); end
|
99
108
|
|
100
109
|
def update(update_hash); end
|
@@ -10,16 +10,16 @@ module Rhoconnect
|
|
10
10
|
end
|
11
11
|
|
12
12
|
# CUD Operations
|
13
|
-
def create
|
14
|
-
_measure_and_process_cud('create'
|
13
|
+
def create
|
14
|
+
_measure_and_process_cud('create')
|
15
15
|
end
|
16
16
|
|
17
|
-
def update
|
18
|
-
_measure_and_process_cud('update'
|
17
|
+
def update
|
18
|
+
_measure_and_process_cud('update')
|
19
19
|
end
|
20
20
|
|
21
|
-
def delete
|
22
|
-
_measure_and_process_cud('delete'
|
21
|
+
def delete
|
22
|
+
_measure_and_process_cud('delete')
|
23
23
|
end
|
24
24
|
|
25
25
|
# Pass through CUD to adapter, no data stored
|
@@ -64,25 +64,25 @@ module Rhoconnect
|
|
64
64
|
res
|
65
65
|
end
|
66
66
|
|
67
|
-
def process_cud
|
67
|
+
def process_cud
|
68
68
|
if @source.cud_queue or @source.queue
|
69
|
-
async(:cud,@source.cud_queue || @source.queue
|
69
|
+
async(:cud,@source.cud_queue || @source.queue)
|
70
70
|
else
|
71
|
-
do_cud
|
71
|
+
do_cud
|
72
72
|
end
|
73
73
|
end
|
74
74
|
|
75
|
-
def do_cud
|
75
|
+
def do_cud
|
76
76
|
return if _auth_op('login') == false
|
77
|
-
self.create
|
78
|
-
self.update
|
79
|
-
self.delete
|
77
|
+
self.create
|
78
|
+
self.update
|
79
|
+
self.delete
|
80
80
|
_auth_op('logoff')
|
81
81
|
end
|
82
82
|
|
83
83
|
def process_query(params=nil)
|
84
84
|
if @source.query_queue or @source.queue
|
85
|
-
async(:query,@source.query_queue || @source.queue,
|
85
|
+
async(:query,@source.query_queue || @source.queue,params)
|
86
86
|
else
|
87
87
|
do_query(params)
|
88
88
|
end
|
@@ -105,10 +105,10 @@ module Rhoconnect
|
|
105
105
|
end
|
106
106
|
|
107
107
|
# Enqueue a job for the source based on job type
|
108
|
-
def async(job_type,queue_name,
|
108
|
+
def async(job_type,queue_name,params=nil)
|
109
109
|
SourceJob.queue = queue_name
|
110
110
|
Resque.enqueue(SourceJob,job_type,@source.id,
|
111
|
-
@source.app_id,@source.user_id,
|
111
|
+
@source.app_id,@source.user_id,params)
|
112
112
|
end
|
113
113
|
|
114
114
|
def push_objects(objects,timeout=10,raise_on_expire=false,rebuild_md=true)
|
@@ -180,108 +180,181 @@ module Rhoconnect
|
|
180
180
|
true
|
181
181
|
end
|
182
182
|
|
183
|
-
def _process_create(
|
184
|
-
# Perform operation
|
183
|
+
def _process_create(modified_recs,key,value)
|
185
184
|
link = @adapter.create value
|
186
185
|
# Store object-id link for the client
|
187
186
|
# If we have a link, store object in client document
|
188
187
|
# Otherwise, store object for delete on client
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
188
|
+
modified_recs.each do |modified_rec|
|
189
|
+
if link
|
190
|
+
modified_rec[:links] ||= {}
|
191
|
+
modified_rec[:links][modified_rec[:key]] = { 'l' => link.to_s }
|
192
|
+
modified_rec[:creates] ||= {}
|
193
|
+
modified_rec[:creates][link.to_s] = value
|
194
|
+
else
|
195
|
+
modified_rec[:deletes] ||= {}
|
196
|
+
modified_rec[:deletes][modified_rec[:key]] = value
|
197
|
+
end
|
197
198
|
end
|
198
199
|
end
|
199
200
|
|
200
|
-
def _process_update(
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
@adapter.update value
|
206
|
-
rescue Exception => e
|
207
|
-
# TODO: This will be slow!
|
208
|
-
cd = client.get_data(:cd)
|
209
|
-
client.put_data(:update_rollback,{key => cd[key]},true) if cd[key]
|
210
|
-
raise e
|
211
|
-
end
|
201
|
+
def _process_update(modified_recs,key,value)
|
202
|
+
# Add id to object hash to forward to backend call
|
203
|
+
value['id'] = key
|
204
|
+
# Perform operation
|
205
|
+
@adapter.update value
|
212
206
|
end
|
213
207
|
|
214
|
-
def _process_delete(
|
208
|
+
def _process_delete(modified_recs,key,value)
|
215
209
|
value['id'] = key
|
216
|
-
# Perform operation
|
217
210
|
@adapter.delete value
|
218
|
-
|
219
|
-
|
211
|
+
# Perform operation
|
212
|
+
modified_recs.each do |modified_rec|
|
213
|
+
modified_rec[:dels] ||= {}
|
214
|
+
modified_rec[:dels][modified_rec[:key]] = value
|
215
|
+
end
|
220
216
|
end
|
221
217
|
|
222
|
-
def _measure_and_process_cud(operation
|
218
|
+
def _measure_and_process_cud(operation)
|
223
219
|
Stats::Record.update("source:#{operation}:#{@source.name}") do
|
224
|
-
_process_cud(operation
|
220
|
+
_process_cud(operation)
|
225
221
|
end
|
226
222
|
end
|
227
223
|
|
228
|
-
def _process_cud(operation
|
224
|
+
def _process_cud(operation)
|
225
|
+
# take everything from the queue and erase it
|
226
|
+
# so that no other process will be able to process it again
|
227
|
+
operation_hashes = []
|
228
|
+
client_ids = []
|
229
|
+
@source.lock(operation) do |s|
|
230
|
+
operation_hashes,client_ids = s.get_zdata(operation)
|
231
|
+
s.flush_zdata(operation)
|
232
|
+
end
|
233
|
+
invalid_meta = @adapter.validate(operation,operation_hashes,client_ids)
|
234
|
+
|
229
235
|
errors,links,deletes,creates,dels = {},{},{},{},{}
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
236
|
+
operation_hashes.each_with_index do |client_operation_data,index|
|
237
|
+
client_id = client_ids[index]
|
238
|
+
|
239
|
+
current_invalid_meta = invalid_meta[index] || {}
|
240
|
+
client_operation_data.each do |key, value|
|
241
|
+
begin
|
242
|
+
continue_loop = true
|
243
|
+
modified_recs = [{:client_id => client_id, :key => key, :value => value }]
|
244
|
+
record_invalid_meta = current_invalid_meta[key] || {}
|
245
|
+
# Remove object from queue
|
246
|
+
client_operation_data.delete(key)
|
247
|
+
|
248
|
+
# skip the rec - if it is a duplicate of some other record
|
249
|
+
next if record_invalid_meta[:duplicate_of]
|
250
|
+
|
251
|
+
# prepare duplicate docs
|
252
|
+
duplicates = record_invalid_meta[:duplicates] || {}
|
253
|
+
duplicates.each do |duplicate|
|
254
|
+
modified_recs << duplicate
|
255
|
+
end
|
256
|
+
|
257
|
+
# raise conflict error if record is marked with one
|
258
|
+
raise SourceAdapterObjectConflictError.new(record_invalid_meta[:error]) if record_invalid_meta[:error]
|
259
|
+
|
260
|
+
# Call on source adapter to process individual object
|
261
|
+
case operation
|
262
|
+
when 'create'
|
263
|
+
_process_create(modified_recs,key,value)
|
264
|
+
when 'update'
|
265
|
+
_process_update(modified_recs,key,value)
|
266
|
+
when 'delete'
|
267
|
+
_process_delete(modified_recs,key,value)
|
268
|
+
end
|
269
|
+
rescue Exception => e
|
270
|
+
log "SourceAdapter raised #{operation} exception: #{e}"
|
271
|
+
log e.backtrace.join("\n")
|
272
|
+
continue_loop = false
|
273
|
+
modified_recs.each do |modified_rec|
|
274
|
+
modified_rec[:errors] ||= {}
|
275
|
+
modified_rec[:errors][modified_rec[:key]] = modified_rec[:value]
|
276
|
+
modified_rec[:errors]["#{modified_rec[:key]}-error"] = {'message'=>e.message}
|
277
|
+
end
|
245
278
|
end
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
279
|
+
|
280
|
+
{ :errors => errors,
|
281
|
+
:links => links,
|
282
|
+
:deletes => deletes,
|
283
|
+
:creates => creates,
|
284
|
+
:dels => dels }.each do |doc_name, doc|
|
285
|
+
modified_recs.each do |modified_rec|
|
286
|
+
doc[modified_rec[:client_id]] ||= {}
|
287
|
+
next unless modified_rec[doc_name]
|
288
|
+
doc[modified_rec[:client_id]].merge!(modified_rec[doc_name])
|
289
|
+
end
|
290
|
+
end
|
291
|
+
break unless continue_loop
|
292
|
+
end
|
293
|
+
|
294
|
+
# Record rest of queue (if something in the middle failed)
|
295
|
+
if not client_operation_data.empty?
|
296
|
+
@source.put_zdata(operation,client_id,client_operation_data,true)
|
253
297
|
end
|
254
298
|
end
|
255
|
-
|
299
|
+
|
300
|
+
# now, process all the modified docs
|
301
|
+
processed_clients = {}
|
302
|
+
client_ids.each do |client_id|
|
303
|
+
processed_clients[client_id] = Client.load(client_id,{:source_name => @source.name}) unless processed_clients[client_id]
|
304
|
+
end
|
256
305
|
{ "delete_page" => deletes,
|
257
306
|
"#{operation}_links" => links,
|
258
|
-
"#{operation}_errors" => errors }.each do |doctype,
|
259
|
-
|
307
|
+
"#{operation}_errors" => errors }.each do |doctype,client_docs|
|
308
|
+
client_docs.each do |client_id,data|
|
309
|
+
client = processed_clients[client_id]
|
310
|
+
client.put_data(doctype,data,true) unless data.empty?
|
311
|
+
end
|
260
312
|
end
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
313
|
+
|
314
|
+
if operation == 'create'
|
315
|
+
total_creates = {}
|
316
|
+
creates.each do |client_id,client_doc|
|
317
|
+
next if client_doc.empty?
|
318
|
+
client = processed_clients[client_id]
|
319
|
+
client.put_data(:cd,client_doc,true)
|
320
|
+
client.update_count(:cd_size,client_doc.size)
|
321
|
+
total_creates.merge!(client_doc)
|
322
|
+
end
|
323
|
+
unless total_creates.empty?
|
324
|
+
@source.lock(:md) do |s|
|
325
|
+
s.put_data(:md,total_creates,true)
|
326
|
+
s.update_count(:md_size,total_creates.size)
|
327
|
+
end
|
267
328
|
end
|
268
329
|
end
|
330
|
+
|
269
331
|
if operation == 'delete'
|
270
332
|
# Clean up deleted objects from master document and corresponding client document
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
333
|
+
total_dels = {}
|
334
|
+
dels.each do |client_id,client_doc|
|
335
|
+
next if client_doc.empty?
|
336
|
+
client = processed_clients[client_id]
|
337
|
+
client.delete_data(:cd,client_doc)
|
338
|
+
client.update_count(:cd_size,-client_doc.size)
|
339
|
+
total_dels.merge!(client_doc)
|
340
|
+
end
|
341
|
+
unless total_dels.empty?
|
342
|
+
@source.lock(:md) do |s|
|
343
|
+
s.delete_data(:md,total_dels)
|
344
|
+
s.update_count(:md_size,-total_dels.size)
|
345
|
+
end
|
276
346
|
end
|
277
347
|
end
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
348
|
+
if operation == 'update'
|
349
|
+
errors.each do |client_id, error_doc|
|
350
|
+
next if error_doc.empty?
|
351
|
+
client = processed_clients[client_id]
|
352
|
+
cd = client.get_data(:cd)
|
353
|
+
error_doc.each do |key, value|
|
354
|
+
client.put_data(:update_rollback,{key => cd[key]},true) if cd[key]
|
355
|
+
end
|
356
|
+
end
|
357
|
+
end
|
285
358
|
end
|
286
359
|
|
287
360
|
# Metadata Operation; source adapter returns json
|
data/lib/rhoconnect/store.rb
CHANGED
@@ -277,6 +277,54 @@ module Rhoconnect
|
|
277
277
|
@@db.rename(srckey,dstkey) if @@db.exists(srckey)
|
278
278
|
end
|
279
279
|
|
280
|
+
def put_zdata(dockey,assoc_key,data={},append=false)
|
281
|
+
return true unless (dockey and assoc_key and data)
|
282
|
+
flush_zdata(dockey) unless append
|
283
|
+
current_score = 0
|
284
|
+
current_score_data = Store.db.zrevrange(dockey,0,0,:with_scores => true)
|
285
|
+
current_score = current_score_data[-1].to_i if current_score_data
|
286
|
+
current_score += 1
|
287
|
+
Store.db.pipelined do
|
288
|
+
data.each do |key,hash_value|
|
289
|
+
unique_record_key = setelement(current_score,assoc_key, key)
|
290
|
+
Store.db.zadd(dockey, current_score, unique_record_key)
|
291
|
+
Store.put_data(unique_record_key,{key => hash_value})
|
292
|
+
end
|
293
|
+
end
|
294
|
+
true
|
295
|
+
end
|
296
|
+
|
297
|
+
# Retrieves set for given dockey,associated key (client_id), obj_hashes
|
298
|
+
def get_zdata(dockey)
|
299
|
+
data = Store.db.zrange(dockey, 0, -1)
|
300
|
+
ret = []
|
301
|
+
keys = []
|
302
|
+
scores = []
|
303
|
+
data.each do |zsetkey|
|
304
|
+
obj_hash = Store.get_data zsetkey
|
305
|
+
score,key,objkey = getelement(zsetkey)
|
306
|
+
if scores[-1] != score
|
307
|
+
ret << obj_hash
|
308
|
+
keys << key
|
309
|
+
scores << score
|
310
|
+
else
|
311
|
+
ret[-1].merge!(obj_hash)
|
312
|
+
end
|
313
|
+
end
|
314
|
+
[ret, keys]
|
315
|
+
end
|
316
|
+
|
317
|
+
# Deletes all keys and their hashes from the Redis DB
|
318
|
+
def flush_zdata(dockey)
|
319
|
+
data = Store.db.zrange(dockey, 0, -1)
|
320
|
+
Store.db.pipelined do
|
321
|
+
data.each do |hash_key|
|
322
|
+
Store.db.del(hash_key)
|
323
|
+
end
|
324
|
+
end
|
325
|
+
Store.db.zremrangebyrank(dockey, 0, -1)
|
326
|
+
end
|
327
|
+
|
280
328
|
alias_method :set_value, :put_value
|
281
329
|
alias_method :set_data, :put_data
|
282
330
|
|
@@ -132,8 +132,8 @@ module Rhoconnect
|
|
132
132
|
if @s.is_pass_through?
|
133
133
|
@ss.pass_through_cud({'create'=> {'temp-id' => record}},nil)
|
134
134
|
else
|
135
|
-
@
|
136
|
-
@ss.process_cud
|
135
|
+
@s.put_zdata(:create,@c.id,{'temp-id' => record},true)
|
136
|
+
@ss.process_cud
|
137
137
|
links = @c.get_data(:create_links)['temp-id']
|
138
138
|
links ? links['l'] : nil
|
139
139
|
end
|
@@ -161,8 +161,8 @@ module Rhoconnect
|
|
161
161
|
if @s.is_pass_through?
|
162
162
|
@ss.pass_through_cud({'update'=> record },nil)
|
163
163
|
else
|
164
|
-
@
|
165
|
-
@ss.process_cud
|
164
|
+
@s.put_zdata(:update,@c.id,record,true)
|
165
|
+
@ss.process_cud
|
166
166
|
end
|
167
167
|
end
|
168
168
|
|
@@ -194,8 +194,8 @@ module Rhoconnect
|
|
194
194
|
if @s.is_pass_through?
|
195
195
|
@ss.pass_through_cud({'delete'=> record },nil)
|
196
196
|
else
|
197
|
-
@
|
198
|
-
@ss.process_cud
|
197
|
+
@s.put_zdata(:delete,@c.id,record,true)
|
198
|
+
@ss.process_cud
|
199
199
|
end
|
200
200
|
end
|
201
201
|
|
data/lib/rhoconnect/version.rb
CHANGED
data/lib/rhoconnect.rb
CHANGED
@@ -46,7 +46,7 @@ module Rhoconnect
|
|
46
46
|
attr_accessor :base_directory, :app_directory, :data_directory,
|
47
47
|
:vendor_directory, :blackberry_bulk_sync, :redis, :environment,
|
48
48
|
:log_disabled, :license, :bulk_sync_poll_interval, :stats, :appserver, :api_token,
|
49
|
-
:raise_on_expired_lock, :lock_duration, :cookie_expire
|
49
|
+
:raise_on_expired_lock, :lock_duration, :cookie_expire, :predefined_sources
|
50
50
|
end
|
51
51
|
|
52
52
|
### Begin Rhoconnect setup methods
|
@@ -70,6 +70,7 @@ module Rhoconnect
|
|
70
70
|
Rhoconnect.lock_duration = get_setting(config,environment,:lock_duration)
|
71
71
|
Rhoconnect.environment = environment
|
72
72
|
Rhoconnect.cookie_expire = get_setting(config,environment,:cookie_expire) || 31536000
|
73
|
+
Rhoconnect.predefined_sources = {}
|
73
74
|
yield self if block_given?
|
74
75
|
Store.create(Rhoconnect.redis)
|
75
76
|
Resque.redis = Store.db
|
@@ -107,6 +108,10 @@ module Rhoconnect
|
|
107
108
|
# load ruby file for source adapter to re-load class
|
108
109
|
load under_score(source_name+'.rb')
|
109
110
|
end
|
111
|
+
|
112
|
+
# load all pre-defined adapters files
|
113
|
+
Dir[File.join(File.dirname(__FILE__),'rhoconnect','predefined_adapters','*.rb')].each { |adapter| load adapter }
|
114
|
+
|
110
115
|
# Create associations for all sources
|
111
116
|
Source.update_associations(app.sources)
|
112
117
|
end
|
@@ -149,7 +154,25 @@ module Rhoconnect
|
|
149
154
|
source_config
|
150
155
|
end
|
151
156
|
|
152
|
-
### End Rhoconnect setup methods
|
157
|
+
### End Rhoconnect setup methods
|
158
|
+
def register_predefined_source(source_name)
|
159
|
+
return if Rhoconnect.predefined_sources.has_key?(source_name)
|
160
|
+
|
161
|
+
Rhoconnect.predefined_sources[source_name] = {:source_loaded => false}
|
162
|
+
end
|
163
|
+
|
164
|
+
def create_predefined_source(source_name,params)
|
165
|
+
source_data = Rhoconnect.predefined_sources[source_name]
|
166
|
+
return unless source_data
|
167
|
+
if source_data[:source_loaded] != true
|
168
|
+
source_config = Rhoconnect.source_config(source_name)
|
169
|
+
source_config[:name] = source_name
|
170
|
+
Source.create(source_config,params)
|
171
|
+
app = App.load(Rhoconnect::APP_NAME)
|
172
|
+
app.sources << source_name
|
173
|
+
source_data[:source_loaded] = true
|
174
|
+
end
|
175
|
+
end
|
153
176
|
|
154
177
|
def check_default_secret!(secret)
|
155
178
|
if secret == '<changeme>'
|
@@ -19,6 +19,35 @@ class SampleAdapter < SourceAdapter
|
|
19
19
|
def sync
|
20
20
|
super
|
21
21
|
end
|
22
|
+
|
23
|
+
def validate(operation,operation_hashes,client_ids)
|
24
|
+
invalid_meta = {}
|
25
|
+
used_ids = {}
|
26
|
+
operation_hashes.each_with_index do |operation_hash,index|
|
27
|
+
client_id = client_ids[index]
|
28
|
+
operation_hash.each do |key,value|
|
29
|
+
if value['force_duplicate_error'] == '1'
|
30
|
+
invalid_meta[index] ||= {}
|
31
|
+
invalid_meta[index][key] ||= {}
|
32
|
+
invalid_meta[index][key][:error] = "Error during #{operation}: object confict detected"
|
33
|
+
end
|
34
|
+
if value['duplicate_of_cid']
|
35
|
+
invalid_meta[index] ||= {}
|
36
|
+
invalid_meta[index][key] ||= {}
|
37
|
+
invalid_meta[index][key][:duplicate_of] = true
|
38
|
+
master_client_id = value['duplicate_of_cid']
|
39
|
+
master_key = value['duplicate_of_key']
|
40
|
+
master_index = value['duplicate_of_queue_index'].to_i
|
41
|
+
|
42
|
+
invalid_meta[master_index] ||= {}
|
43
|
+
invalid_meta[master_index][master_key] ||= {}
|
44
|
+
invalid_meta[master_index][master_key][:duplicates] ||= []
|
45
|
+
invalid_meta[master_index][master_key][:duplicates] << {:client_id => client_id, :key => key, :value => value}
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
invalid_meta
|
50
|
+
end
|
22
51
|
|
23
52
|
def create(create_hash)
|
24
53
|
Store.put_data('test_create_storage',{create_hash['_id']=>create_hash},true)
|
@@ -9,7 +9,7 @@ describe "SourceJob" do
|
|
9
9
|
|
10
10
|
it "should perform process_query" do
|
11
11
|
set_state('test_db_storage' => @data)
|
12
|
-
SourceJob.perform('query',@s.id,@s.app_id,@s.user_id,nil
|
12
|
+
SourceJob.perform('query',@s.id,@s.app_id,@s.user_id,nil)
|
13
13
|
verify_result(@s.docname(:md) => @data,
|
14
14
|
@s.docname(:md_size) => @data.size.to_s)
|
15
15
|
end
|
@@ -17,13 +17,13 @@ describe "SourceJob" do
|
|
17
17
|
it "should perform process_cud" do
|
18
18
|
expected = {'backend_id'=>@product1}
|
19
19
|
@product1['link'] = 'abc'
|
20
|
-
|
21
|
-
SourceJob.perform('cud',@s.id,@s.app_id,@s.user_id
|
20
|
+
set_zstate({@s.docname(:create) => {'1'=>@product1}}, @c.id, true)
|
21
|
+
SourceJob.perform('cud',@s.id,@s.app_id,@s.user_id,nil)
|
22
|
+
verify_zresult(@s.docname(:create) => [])
|
22
23
|
verify_result(@s.docname(:md) => expected,
|
23
24
|
@s.docname(:md_size) => expected.size.to_s,
|
24
25
|
@c.docname(:cd) => expected,
|
25
|
-
@c.docname(:cd_size) => expected.size.to_s
|
26
|
-
@c.docname(:create) => {})
|
26
|
+
@c.docname(:cd_size) => expected.size.to_s)
|
27
27
|
end
|
28
28
|
end
|
29
29
|
end
|
data/spec/source_adapter_spec.rb
CHANGED
@@ -33,6 +33,16 @@ describe "SourceAdapter" do
|
|
33
33
|
@sa.class.name.should == @s.name
|
34
34
|
end
|
35
35
|
|
36
|
+
it "should create all existing pre-defined adapters" do
|
37
|
+
Rhoconnect.predefined_sources.keys.sort.should == ['RhoInternalBenchmarkAdapter'].sort
|
38
|
+
Rhoconnect.predefined_sources.each do |adapter_name, filename|
|
39
|
+
pas = Source.load(adapter_name, @s_params)
|
40
|
+
pas.should_not == nil
|
41
|
+
pa = SourceAdapter.create(pas)
|
42
|
+
pa.class.name.should == "Rhoconnect::#{adapter_name}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
36
46
|
it "should create DynamicAdapter" do
|
37
47
|
@sa1 = SourceAdapter.create(@s2)
|
38
48
|
@sa1.class.name.should == 'Rhoconnect::DynamicAdapter'
|