rhoconnect 3.3.6 → 3.4.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (152) hide show
  1. data/CHANGELOG.md +40 -4
  2. data/Gemfile +2 -2
  3. data/Gemfile.lock +27 -25
  4. data/bench/benchapp/Gemfile +7 -27
  5. data/bench/benchapp/config.ru +9 -31
  6. data/bench/blobapp/Gemfile +7 -27
  7. data/bench/blobapp/config.ru +9 -29
  8. data/bench/lib/bench.rb +8 -1
  9. data/bench/lib/bench/test_data.rb +4 -1
  10. data/bench/scripts/blob_cud_script.rb +4 -0
  11. data/bench/scripts/cud_script.rb +7 -1
  12. data/bench/scripts/helpers.rb +1 -1
  13. data/bench/scripts/test_query_script.rb +20 -7
  14. data/bench/spec/bench_spec_helper.rb +3 -1
  15. data/bin/rhoconnect +22 -12
  16. data/commands/{commands/dtach_commands → dtach}/dtach_about.rb +0 -0
  17. data/commands/{commands/dtach_commands → dtach}/dtach_install.rb +0 -0
  18. data/commands/{commands/redis_commands → dtach}/redis_attach.rb +0 -0
  19. data/commands/execute.rb +14 -15
  20. data/commands/generators/update.rb +26 -0
  21. data/commands/{commands/redis_commands → redis}/redis_about.rb +0 -0
  22. data/commands/redis/redis_download.rb +13 -0
  23. data/commands/redis/redis_install.rb +26 -0
  24. data/commands/{commands/redis_commands → redis}/redis_make.rb +0 -0
  25. data/commands/{commands/redis_commands → redis}/redis_restart.rb +3 -2
  26. data/commands/{commands/redis_commands → redis}/redis_start.rb +0 -0
  27. data/commands/{commands/redis_commands → redis}/redis_startbg.rb +0 -0
  28. data/commands/{commands/redis_commands → redis}/redis_stop.rb +3 -2
  29. data/commands/{commands/rhoconnect → rhoconnect}/clean_start.rb +0 -0
  30. data/commands/{commands/rhoconnect → rhoconnect}/config.rb +7 -2
  31. data/commands/{commands/rhoconnect → rhoconnect}/create_user.rb +0 -0
  32. data/commands/{commands/rhoconnect → rhoconnect}/delete_device.rb +0 -0
  33. data/commands/{commands/rhoconnect → rhoconnect}/delete_user.rb +0 -0
  34. data/commands/{commands/rhoconnect → rhoconnect}/flushdb.rb +4 -4
  35. data/commands/{commands/rhoconnect → rhoconnect}/get_token.rb +0 -0
  36. data/commands/{commands/rhoconnect → rhoconnect}/reset.rb +0 -0
  37. data/commands/{commands/rhoconnect → rhoconnect}/reset_refresh.rb +0 -0
  38. data/commands/{commands/rhoconnect → rhoconnect}/restart.rb +0 -0
  39. data/commands/{commands/rhoconnect → rhoconnect}/secret.rb +0 -0
  40. data/commands/{commands/rhoconnect → rhoconnect}/set_admin_password.rb +0 -0
  41. data/commands/{commands/rhoconnect → rhoconnect}/spec.rb +0 -0
  42. data/commands/rhoconnect/start.rb +27 -0
  43. data/commands/{commands/rhoconnect → rhoconnect}/startbg.rb +0 -0
  44. data/commands/{commands/rhoconnect → rhoconnect}/startdebug.rb +2 -2
  45. data/commands/{commands/rhoconnect → rhoconnect}/stop.rb +3 -4
  46. data/commands/{commands/rhoconnect → rhoconnect}/version.rb +0 -0
  47. data/commands/{commands/rhoconnect → rhoconnect}/web.rb +0 -0
  48. data/commands/rhoconnect_attach/attach.rb +10 -0
  49. data/commands/rhoconnect_console/console.rb +16 -0
  50. data/commands/{commands/rhoconnect → rhoconnect_console}/console_helper.rb +0 -0
  51. data/commands/{commands/rhoconnect → rhoconnect_war}/war.rb +0 -0
  52. data/commands/{commands/redis_commands → utilities}/redis_runner.rb +22 -19
  53. data/commands/utilities/utilities.rb +6 -0
  54. data/doc/benchmarks.txt +2 -2
  55. data/doc/bulk-sync.txt +12 -1
  56. data/doc/client-java.txt +3 -3
  57. data/doc/client-objc.txt +1 -1
  58. data/doc/client.txt +5 -5
  59. data/doc/command-line.txt +80 -135
  60. data/doc/deploying.txt +119 -12
  61. data/doc/extending-rhoconnect-server.txt +1 -1
  62. data/doc/heroku-addon.txt +119 -23
  63. data/doc/install.txt +101 -39
  64. data/doc/java-plugin.txt +2 -2
  65. data/doc/licensing.txt +1 -1
  66. data/doc/plugin-intro.txt +3 -1
  67. data/doc/preparing-production.txt +4 -4
  68. data/doc/public/cli.txt +2 -2
  69. data/doc/push-backend-setup.txt +11 -1
  70. data/doc/push-client-setup.txt +72 -2
  71. data/doc/push-server-setup.txt +129 -8
  72. data/doc/rails-plugin.txt +245 -40
  73. data/doc/rest-api.txt +10 -6
  74. data/doc/rhoconnect-calculator.txt +237 -0
  75. data/doc/rhoconnect-redis-stack.txt +35 -0
  76. data/doc/session-and-configuration.txt +24 -0
  77. data/doc/settings.txt +51 -41
  78. data/doc/source-adapters.txt +45 -45
  79. data/doc/stats-middleware.txt +2 -2
  80. data/doc/supported-platforms.txt +6 -6
  81. data/doc/testing.txt +2 -2
  82. data/doc/tutorial.txt +63 -63
  83. data/examples/simple/Gemfile +7 -35
  84. data/examples/simple/config.ru +8 -26
  85. data/examples/simple/sources/product.rb +6 -6
  86. data/generators/rhoconnect.rb +5 -0
  87. data/generators/templates/application/Gemfile +7 -37
  88. data/generators/templates/application/Rakefile +8 -0
  89. data/generators/templates/application/config.ru +12 -31
  90. data/generators/templates/application/rcgemfile +44 -0
  91. data/generators/templates/application/settings/settings.yml +7 -5
  92. data/install.sh +4 -4
  93. data/installer/unix-like/create_texts.rb +7 -2
  94. data/installer/unix-like/rho_connect_install_constants.rb +2 -2
  95. data/installer/unix-like/rho_connect_install_installers.rb +1 -16
  96. data/lib/rhoconnect.rb +51 -38
  97. data/lib/rhoconnect/api/app/query.rb +4 -1
  98. data/lib/rhoconnect/api/app/search.rb +4 -1
  99. data/lib/rhoconnect/api/client/list_client_docs.rb +3 -1
  100. data/lib/rhoconnect/api/user/ping.rb +1 -5
  101. data/lib/rhoconnect/application/init.rb +43 -0
  102. data/lib/rhoconnect/async.rb +11 -6
  103. data/lib/rhoconnect/client_sync.rb +30 -37
  104. data/lib/rhoconnect/document.rb +4 -0
  105. data/lib/rhoconnect/graph_helper.rb +74 -56
  106. data/lib/rhoconnect/middleware/helpers.rb +4 -0
  107. data/lib/rhoconnect/ping.rb +1 -0
  108. data/lib/rhoconnect/ping/gcm.rb +58 -0
  109. data/lib/rhoconnect/predefined_adapters/bench_adapter.rb +7 -1
  110. data/lib/rhoconnect/source.rb +70 -56
  111. data/lib/rhoconnect/source_sync.rb +33 -5
  112. data/lib/rhoconnect/store.rb +358 -110
  113. data/lib/rhoconnect/user.rb +8 -0
  114. data/lib/rhoconnect/utilities.rb +16 -14
  115. data/lib/rhoconnect/version.rb +1 -1
  116. data/lib/rhoconnect/web-console/models/client.js +1 -1
  117. data/lib/rhoconnect/web-console/public/UNVR67bold.ttf +0 -0
  118. data/lib/rhoconnect/web-console/public/bootstrap.css +6 -0
  119. data/lib/rhoconnect/web-console/public/logo.png +0 -0
  120. data/lib/rhoconnect/web-console/server.rb +13 -11
  121. data/lib/rhoconnect/web-console/templates/index.erb +5 -5
  122. data/lib/rhoconnect/web-console/templates/jqplot.erb +1 -0
  123. data/lib/rhoconnect/web-console/views/doc.js +0 -4
  124. data/lib/rhoconnect/web-console/views/home.js +2 -1
  125. data/lib/rhoconnect/web-console/views/new_ping.js +11 -6
  126. data/lib/rhoconnect/web-console/views/stats.js +9 -5
  127. data/rhoconnect.gemspec +6 -4
  128. data/spec/api/app/fast_update_spec.rb +2 -2
  129. data/spec/api/source/get_source_params_spec.rb +1 -0
  130. data/spec/apps/rhotestapp/settings/settings.yml +5 -5
  131. data/spec/client_sync_spec.rb +3 -14
  132. data/spec/perf/perf_spec_helper.rb +11 -7
  133. data/spec/perf/store_perf_spec.rb +88 -11
  134. data/spec/ping/gcm_spec.rb +99 -0
  135. data/spec/server/server_spec.rb +7 -0
  136. data/spec/server/stats_spec.rb +9 -2
  137. data/spec/source_sync_spec.rb +29 -0
  138. data/spec/spec_helper.rb +40 -38
  139. data/spec/stats/record_spec.rb +18 -9
  140. data/spec/store_spec.rb +128 -19
  141. data/spec/testdata/10000-data.txt +0 -0
  142. data/spec/testdata/5-data.txt +0 -0
  143. data/spec/testdata/5000-data.txt +0 -0
  144. data/tasks/jasmine.rake +1 -0
  145. data/tasks/redis.rake +16 -13
  146. metadata +71 -39
  147. data/commands/commands/redis_commands/redis_download.rb +0 -33
  148. data/commands/commands/redis_commands/redis_install.rb +0 -26
  149. data/commands/commands/rhoconnect/attach.rb +0 -8
  150. data/commands/commands/rhoconnect/console.rb +0 -15
  151. data/commands/commands/rhoconnect/start.rb +0 -18
  152. data/commands/utilities/dtach_installed.rb +0 -10
@@ -2,3 +2,4 @@ require 'rhoconnect/ping/android'
2
2
  require 'rhoconnect/ping/apple'
3
3
  require 'rhoconnect/ping/blackberry'
4
4
  require 'rhoconnect/ping/rhoconnect_push'
5
+ require 'rhoconnect/ping/gcm'
@@ -0,0 +1,58 @@
1
+ require 'rest_client'
2
+
3
+ module Rhoconnect
4
+ class Gcm
5
+ class InvalidApiKey < Exception; end
6
+ class GCMPingError < Exception; end
7
+
8
+ def self.ping(params)
9
+ begin
10
+ gcm_api_key = Rhoconnect.settings[:gcm_api_key]
11
+ raise InvalidApiKey.new("Missing `:gcm_api_key:` option in settings/settings.yml") unless gcm_api_key
12
+
13
+ send_ping_to_device(gcm_api_key, params)
14
+ rescue InvalidApiKey => error
15
+ log error
16
+ log error.backtrace.join("\n")
17
+ raise error
18
+ rescue Exception => error
19
+ log error
20
+ log error.backtrace.join("\n")
21
+ raise error
22
+ end
23
+ end
24
+
25
+ def self.send_ping_to_device(api_key,params)
26
+ RestClient.post(
27
+ 'https://android.googleapis.com/gcm/send', gcm_message(params).to_json,
28
+ :authorization => "key=#{api_key}",
29
+ :content_type => :json
30
+ ) do |response, request, result, &block|
31
+ # return exceptions based on response code & body
32
+ case response.code
33
+ when 200
34
+ if response.body =~ /^Error=(.*)$/
35
+ raise GCMPingError.new("GCM ping error: #{$1 || ''}")
36
+ end
37
+ response.return!(request, result, &block)
38
+ when 401, 403
39
+ raise InvalidApiKey.new("Invalid GCM api key. Obtain new api key from GCM service.")
40
+ end
41
+ end
42
+ end
43
+
44
+ def self.gcm_message(params)
45
+ params.reject! {|k,v| v.nil? || v.length == 0}
46
+ data = {}
47
+ data['registration_ids'] = [params['device_pin'].to_s]
48
+ data['collapse_key'] = (rand * 100000000).to_i.to_s
49
+ data['data'] = {}
50
+ data['data']['do_sync'] = params['sources'] ? params['sources'].join(',') : ''
51
+ data['data']['alert'] = params['message'] if params['message']
52
+ data['data']['vibrate'] = params['vibrate'] if params['vibrate']
53
+ data['data']['sound'] = params['sound'] if params['sound']
54
+ data['data']['phone_id'] = params['phone_id'] if params['phone_id']
55
+ data
56
+ end
57
+ end
58
+ end
@@ -57,7 +57,13 @@ module Rhoconnect
57
57
  end
58
58
 
59
59
  def db_name
60
- "test_db_storage:#{@source.app_id}:#{@source.user_id}"
60
+ res = ''
61
+ if @source.user_id[0..1] == 'nq'
62
+ res = "test_db_storage:#{@source.app_id}:nquser"
63
+ else
64
+ res = "test_db_storage:#{@source.app_id}:benchuser"
65
+ end
66
+ res
61
67
  end
62
68
 
63
69
  def lock_name
@@ -4,10 +4,10 @@ module Rhoconnect
4
4
  @@string_fields = []
5
5
  @@integer_fields = []
6
6
  attr_accessor :id
7
-
7
+
8
8
  class << self
9
9
  attr_accessor :validates_presence
10
-
10
+
11
11
  def create(fields,params)
12
12
  if self.validates_presence
13
13
  self.validates_presence.each do |field|
@@ -15,12 +15,12 @@ module Rhoconnect
15
15
  end
16
16
  end
17
17
  end
18
-
18
+
19
19
  def define_fields(string_fields = [], integer_fields = [])
20
20
  @@string_fields,@@integer_fields = string_fields,integer_fields
21
21
  integer_fields.each do |attrib|
22
22
  define_method("#{attrib}=") do |value|
23
- value = (value.nil?) ? nil : value.to_i
23
+ value = (value.nil?) ? nil : value.to_i
24
24
  @@model_data[self.name.to_sym][attrib.to_sym] = value
25
25
  end
26
26
  define_method("#{attrib}") do
@@ -34,7 +34,7 @@ module Rhoconnect
34
34
  if attrib == :name
35
35
  instance_variable_set(:@name, value)
36
36
  name = value
37
- else
37
+ else
38
38
  name = self.name
39
39
  end
40
40
  @@model_data[name.to_sym] ||= {} # TODO: shouldn't be nil here
@@ -47,14 +47,14 @@ module Rhoconnect
47
47
  @@integer_fields << :poll_interval unless @@integer_fields.include?(:poll_interval)
48
48
  end
49
49
  end
50
-
50
+
51
51
  def validates_presence_of(*names)
52
52
  self.validates_presence ||= []
53
53
  names.each do |name|
54
54
  self.validates_presence << name
55
55
  end
56
56
  end
57
-
57
+
58
58
  def is_exist?(id)
59
59
  !@@model_data[id.to_sym].nil?
60
60
  end
@@ -67,14 +67,14 @@ module Rhoconnect
67
67
  downcase
68
68
  end
69
69
  end
70
-
70
+
71
71
  def update_fields(fields)
72
72
  fields.each do |name,value|
73
- arg = "#{name}=".to_sym
73
+ arg = "#{name}=".to_sym
74
74
  self.send(arg, value)
75
75
  end
76
76
  end
77
-
77
+
78
78
  def to_array
79
79
  res = []
80
80
  @@string_fields.each do |field|
@@ -86,24 +86,24 @@ module Rhoconnect
86
86
  res
87
87
  end
88
88
  end
89
-
89
+
90
90
  class Source < MemoryModel
91
91
  attr_accessor :app_id, :user_id
92
-
92
+
93
93
  validates_presence_of :name
94
-
94
+
95
95
  include Document
96
96
  include LockOps
97
-
97
+
98
98
  # source fields
99
- define_fields([:id, :rho__id, :name, :url, :login, :password, :callback_url, :partition_type, :sync_type,
100
- :queue, :query_queue, :cud_queue, :belongs_to, :has_many, :pass_through], [:source_id, :priority, :retry_limit, :simulate_time])
101
-
99
+ define_fields([:id, :rho__id, :name, :url, :login, :password, :callback_url, :partition_type, :sync_type,
100
+ :queue, :query_queue, :cud_queue, :belongs_to, :has_many, :pass_through, :push_notify], [:source_id, :priority, :retry_limit, :simulate_time])
101
+
102
102
  def initialize(fields)
103
103
  self.name = fields['name'] || fields[:name]
104
104
  update_fields(fields)
105
105
  end
106
-
106
+
107
107
  def self.set_defaults(fields)
108
108
  fields[:url] ||= ''
109
109
  fields[:login] ||= ''
@@ -118,8 +118,9 @@ module Rhoconnect
118
118
  fields[:schema] = fields[:schema].to_json if fields[:schema]
119
119
  fields[:retry_limit] = fields[:retry_limit] ? fields[:retry_limit] : 0
120
120
  fields[:simulate_time] = fields[:simulate_time] ? fields[:simulate_time] : 0
121
+ fields[:push_notify] = fields[:push_notify] ? fields[:push_notify] : 'false'
121
122
  end
122
-
123
+
123
124
  def self.create(fields,params)
124
125
  fields = fields.with_indifferent_access # so we can access hash keys as symbols
125
126
  super(fields,params)
@@ -129,23 +130,23 @@ module Rhoconnect
129
130
  obj.assign_args(params)
130
131
  obj
131
132
  end
132
-
133
+
133
134
  def self.load(obj_id,params)
134
135
  validate_attributes(params)
135
-
136
- # if source is pre-defined
136
+
137
+ # if source is pre-defined
137
138
  # create it dynamically here
138
139
  Rhoconnect.create_predefined_source(obj_id,params)
139
-
140
+
140
141
  model_hash = @@model_data[obj_id.to_sym]
141
142
  obj = new(model_hash) if model_hash
142
143
  if obj
143
144
  obj = obj.dup
144
- obj.assign_args(params)
145
+ obj.assign_args(params)
145
146
  end
146
147
  obj
147
148
  end
148
-
149
+
149
150
  def self.update_associations(sources)
150
151
  params = {:app_id => APP_NAME,:user_id => '*'}
151
152
  sources.each { |source| Source.load(source, params).has_many = nil }
@@ -168,7 +169,7 @@ module Rhoconnect
168
169
  end
169
170
  end
170
171
  end
171
-
172
+
172
173
  def self.delete_all
173
174
  params = {:app_id => APP_NAME,:user_id => '*'}
174
175
  @@model_data.each { |k,v| Source.load(k,params).flash_store_data }
@@ -177,9 +178,9 @@ module Rhoconnect
177
178
 
178
179
  def assign_args(params)
179
180
  self.user_id = params[:user_id]
180
- self.app_id = params[:app_id]
181
+ self.app_id = params[:app_id]
181
182
  end
182
-
183
+
183
184
  def blob_attribs
184
185
  return '' unless self.schema
185
186
  schema = JSON.parse(self.schema)
@@ -189,62 +190,62 @@ module Rhoconnect
189
190
  if values.include?('blob')
190
191
  attrib = key.dup
191
192
  attrib << "," + (values.include?('overwrite') ? '1' : '0')
192
- blob_attribs << attrib
193
+ blob_attribs << attrib
193
194
  end
194
195
  end
195
196
  blob_attribs.sort.join(',')
196
197
  end
197
-
198
+
198
199
  def update(fields)
199
200
  fields = fields.with_indifferent_access # so we can access hash keys as symbols
200
201
  self.class.set_defaults(fields)
201
202
  end
202
-
203
+
203
204
  def clone(src_doctype,dst_doctype)
204
205
  Store.clone(docname(src_doctype),docname(dst_doctype))
205
206
  end
206
-
207
+
207
208
  def poll_interval
208
209
  value = Store.get_value(poll_interval_key)
209
210
  value ? value.to_i : nil
210
211
  end
211
-
212
+
212
213
  def poll_interval=(interval)
213
214
  Store.put_value(poll_interval_key, interval)
214
215
  end
215
-
216
+
216
217
  # Return the user associated with a source
217
218
  def user
218
219
  User.load(self.user_id)
219
220
  end
220
-
221
+
221
222
  # Return the app the source belongs to
222
223
  def app
223
224
  App.load(self.app_id)
224
225
  end
225
-
226
+
226
227
  def schema
227
228
  self.get_value(:schema)
228
229
  end
229
-
230
+
230
231
  def read_state
231
232
  id = {:app_id => self.app_id,:user_id => user_by_partition,
232
233
  :source_name => self.name}
233
234
  load_read_state || ReadState.create(id)
234
235
  end
235
-
236
+
236
237
  def load_read_state
237
238
  id = {:app_id => self.app_id,:user_id => user_by_partition,
238
239
  :source_name => self.name}
239
240
  ReadState.load(id)
240
241
  end
241
-
242
+
242
243
  def delete_user_read_state
243
244
  id = {:app_id => self.app_id,:user_id => user_by_partition,
244
245
  :source_name => self.name}
245
246
  ReadState.delete_user(id)
246
247
  end
247
-
248
+
248
249
  def doc_suffix(doctype)
249
250
  "#{user_by_partition}:#{self.name}:#{doctype.to_s}"
250
251
  end
@@ -259,24 +260,24 @@ module Rhoconnect
259
260
  flash_store_data
260
261
  @@model_data.delete(rho__id.to_sym) if rho__id
261
262
  end
262
-
263
+
263
264
  def partition
264
265
  self.partition_type.to_sym
265
266
  end
266
-
267
+
267
268
  def partition=(value)
268
269
  self.partition_type = value
269
270
  end
270
-
271
+
271
272
  def user_by_partition
272
273
  self.partition.to_sym == :user ? self.user_id : '__shared__'
273
274
  end
274
-
275
+
275
276
  def check_refresh_time
276
- self.poll_interval == 0 or
277
+ self.poll_interval == 0 or
277
278
  (self.poll_interval != -1 and self.read_state.refresh_time <= Time.now.to_i)
278
279
  end
279
-
280
+
280
281
  def if_need_refresh(client_id=nil,params=nil)
281
282
  need_refresh = lock(:md) do |s|
282
283
  check = check_refresh_time
@@ -286,23 +287,23 @@ module Rhoconnect
286
287
  end
287
288
  yield client_id,params if need_refresh
288
289
  end
289
-
290
+
290
291
  def rewind_refresh_time(query_failure)
291
292
  return if self.poll_interval == 0
292
293
  lock(:md) do |s|
293
294
  rewind_time = false
294
- # reset number of retries
295
+ # reset number of retries
295
296
  # and prev_refresh_time on succesfull query
296
297
  # or if last refresh was more than 'poll_interval' time ago
297
298
  if not query_failure or ((Time.now.to_i - self.read_state.prev_refresh_time) >= self.poll_interval)
298
299
  # we need to reset the prev_refresh_time here
299
300
  # otherwise in case of expired poll interval
300
- # and repeating failures - it will reset the counter
301
+ # and repeating failures - it will reset the counter
301
302
  # on every error
302
303
  self.read_state.prev_refresh_time = Time.now.to_i
303
304
  self.read_state.retry_counter = 0
304
305
  end
305
-
306
+
306
307
  # rewind the refresh time on failure
307
308
  # if retry limit is not reached
308
309
  if query_failure
@@ -315,22 +316,35 @@ module Rhoconnect
315
316
  self.read_state.retry_counter = 0
316
317
  end
317
318
  end
318
-
319
+
319
320
  if rewind_time
320
321
  self.read_state.refresh_time = self.read_state.prev_refresh_time
321
322
  end
322
- end
323
+ end
323
324
  end
324
-
325
+
325
326
  def is_pass_through?
326
- self.pass_through and self.pass_through == 'true'
327
+ self.pass_through and self.pass_through.to_s == 'true'
328
+ end
329
+
330
+ def push_notify?
331
+ self.push_notify and self.push_notify.to_s == 'true'
332
+ end
333
+
334
+ def announce_changes
335
+ return unless push_notify?
336
+ # TODO: currently we're not allowing 'Broadcast' push to all users for :app partitioned sources
337
+ return if self.partition.to_sym == :app
338
+
339
+ users = [self.user_id]
340
+ User.ping({'user_id' => users, 'sources' => [self.name]})
327
341
  end
328
-
342
+
329
343
  private
330
344
  def poll_interval_key
331
345
  "source:#{self.name}:poll_interval"
332
346
  end
333
-
347
+
334
348
  def self.validate_attributes(params)
335
349
  raise ArgumentError.new('Missing required attribute user_id') unless params[:user_id]
336
350
  raise ArgumentError.new('Missing required attribute app_id') unless params[:app_id]
@@ -117,13 +117,38 @@ module Rhoconnect
117
117
  @source.put_data(:md, new_objs, true)
118
118
  @source.update_count(:md_size,diff_count)
119
119
  end
120
+ @source.announce_changes
120
121
  end
121
122
 
122
- def fast_update(orig_hash, new_hash, timeout=10,raise_on_expire=false)
123
+ def fast_update(remove_hash, new_hash, timeout=10,raise_on_expire=false)
124
+ return unless ((remove_hash and remove_hash.size > 0) or (new_hash and new_hash.size > 0))
123
125
  @source.lock(:md,timeout,raise_on_expire) do |s|
124
- @source.delete_data(:md, orig_hash)
125
- @source.put_data(:md, new_hash, true)
126
+ # get the objects from DB, remove prev attr data, add new attr data
127
+ update_keys = Set.new
128
+ update_keys += Set.new(remove_hash.keys) if remove_hash
129
+ update_keys += Set.new(new_hash.keys) if new_hash
130
+ objs_to_update = @source.get_objects(:md, update_keys.to_a) || {}
131
+ diff_count = -objs_to_update.size
132
+ # remove old values from DB
133
+ @source.delete_data(:md, objs_to_update)
134
+ # update data
135
+ remove_hash.each do |key, obj|
136
+ next unless objs_to_update[key]
137
+ obj.each do |attrib, value|
138
+ objs_to_update[key].delete(attrib)
139
+ objs_to_update.delete(key) if objs_to_update[key].empty?
140
+ end
141
+ end if remove_hash
142
+ new_hash.each do |key, obj|
143
+ objs_to_update[key] ||= {}
144
+ objs_to_update[key].merge!(obj)
145
+ end if new_hash
146
+ # store new data into DB
147
+ @source.put_data(:md, objs_to_update, true)
148
+ diff_count += objs_to_update.size
149
+ @source.update_count(:md_size,diff_count)
126
150
  end
151
+ @source.announce_changes
127
152
  end
128
153
 
129
154
  def fast_delete(delete_objs, timeout=10,raise_on_expire=false)
@@ -132,6 +157,7 @@ module Rhoconnect
132
157
  @source.delete_data(:md, delete_objs)
133
158
  @source.update_count(:md_size,diff_count)
134
159
  end
160
+ @source.announce_changes
135
161
  end
136
162
 
137
163
  def push_objects(objects,timeout=10,raise_on_expire=false,rebuild_md=true)
@@ -158,7 +184,8 @@ module Rhoconnect
158
184
  end
159
185
 
160
186
  @source.update_count(:md_size,diff_count)
161
- end
187
+ end
188
+ @source.announce_changes
162
189
  end
163
190
 
164
191
  def push_deletes(objects,timeout=10,raise_on_expire=false,rebuild_md=true)
@@ -184,7 +211,8 @@ module Rhoconnect
184
211
  end
185
212
 
186
213
  @source.update_count(:md_size,diff_count)
187
- end
214
+ end
215
+ @source.announce_changes
188
216
  end
189
217
 
190
218
  private