perfectqueue 0.9.1 → 0.9.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cec4a6907599be03eb95b756075c114c1a282218
4
- data.tar.gz: 3cc969e794964142212690c24eef4aab1c45e847
3
+ metadata.gz: 7274d143afaecb7d6ee09cac6d4e287813dcf1bc
4
+ data.tar.gz: 25c4271e2bbcb2734c92234a73c59121e383834c
5
5
  SHA512:
6
- metadata.gz: 99bbd684d883988af719392e15e37446eec1b7404d1c3a661875156fc4137ab2e6ddf090e706a0c13449a0fc17fcdba1e2d19d54fc3d8db17e018081f3cb4326
7
- data.tar.gz: 8f2be0558cf06f6caf6664c7cf77aaddabb3470b632495bfdd0a8790cac72592072e58fd17051fb7a04459c8f5b369a77343f7d50135b8402e5c7ba40c52995d
6
+ metadata.gz: cc0acb6de0b1771606a5a8047f48d6c6e904722af0416291951cb87cfca8a65bd16b501099a1540e0f55ab7f9a41c650321b6cc87add520ead66b69acf61def2
7
+ data.tar.gz: 1b85520494ad5059f0dc5dc187eeab5810a51bd707e6931b21e1663c0425b0fcf05921ebb424f7aa1102e744a3f1e317cda7d0fe55d3fd36e947f895ba0420e3
data/ChangeLog CHANGED
@@ -1,3 +1,7 @@
1
+ == 2016-10-07 version 0.9.2
2
+
3
+ * Use v08's strategy if resource limit is used (#55)
4
+
1
5
  == 2016-09-23 version 0.9.1
2
6
 
3
7
  * FOR UPDATE is not required while with GET_LOCK() (#54)
@@ -78,55 +78,7 @@ module PerfectQueue
78
78
  # connection test
79
79
  }
80
80
 
81
- # MySQL's CONNECTION_ID() is a 64bit unsigned integer from the
82
- # server's internal thread ID counter. It is unique while the MySQL
83
- # server is running.
84
- # https://bugs.mysql.com/bug.php?id=19806
85
- #
86
- # An acquired task is marked with next_timeout and CONNECTION_ID().
87
- # Therefore while alive_time is not changed and we don't restart
88
- # the server in 1 second, they won't conflict.
89
- if config[:disable_resource_limit]
90
- @update_sql = <<SQL
91
- UPDATE `#{@table}`
92
- JOIN (
93
- SELECT id
94
- FROM `#{@table}` FORCE INDEX (`index_#{@table}_on_timeout`)
95
- WHERE #{EVENT_HORIZON} < timeout AND timeout <= :now
96
- ORDER BY timeout ASC
97
- LIMIT :max_acquire) AS t1 USING(id)
98
- SET timeout=:next_timeout, owner=CONNECTION_ID()
99
- SQL
100
- @sql = <<SQL
101
- SELECT id, timeout, data, created_at, resource
102
- FROM `#{@table}`
103
- WHERE timeout = ? AND owner = CONNECTION_ID()
104
- SQL
105
- else
106
- @update_sql = <<SQL
107
- UPDATE `#{@table}`
108
- JOIN (
109
- SELECT id, IFNULL(max_running, 1) / (IFNULL(running, 0) + 1) AS weight
110
- FROM `#{@table}`
111
- LEFT JOIN (
112
- SELECT resource, COUNT(1) AS running
113
- FROM `#{@table}` AS t1
114
- WHERE timeout > :now AND resource IS NOT NULL
115
- GROUP BY resource
116
- ) AS t2 USING(resource)
117
- WHERE #{EVENT_HORIZON} < timeout AND timeout <= :now AND IFNULL(max_running - running, 1) > 0
118
- ORDER BY weight DESC, timeout ASC
119
- LIMIT :max_acquire
120
- ) AS t3 USING (id)
121
- SET timeout = :next_timeout, owner = CONNECTION_ID()
122
- SQL
123
- @sql = <<SQL
124
- SELECT id, timeout, data, created_at, resource, max_running
125
- FROM `#{@table}`
126
- WHERE timeout = ? AND owner = CONNECTION_ID()
127
- SQL
128
- end
129
-
81
+ @disable_resource_limit = config[:disable_resource_limit]
130
82
  @cleanup_interval = config[:cleanup_interval] || DEFAULT_DELETE_INTERVAL
131
83
  # If cleanup_interval > max_request_per_child / max_acquire,
132
84
  # some processes won't run DELETE query.
@@ -240,7 +192,6 @@ SQL
240
192
  def acquire(alive_time, max_acquire, options)
241
193
  now = (options[:now] || Time.now).to_i
242
194
  next_timeout = now + alive_time
243
- tasks = nil
244
195
  t0 = nil
245
196
 
246
197
  if @cleanup_interval_count <= 0
@@ -252,27 +203,11 @@ SQL
252
203
  }
253
204
  end
254
205
 
255
- connect_locked {
256
- t0=Process.clock_gettime(Process::CLOCK_MONOTONIC)
257
- n = @db[@update_sql, next_timeout: next_timeout, now: now, max_acquire: max_acquire].update
258
- if n <= 0
259
- return nil
260
- end
261
- @table_unlock.call
262
-
263
- tasks = []
264
- @db.fetch(@sql, next_timeout) {|row|
265
- attributes = create_attributes(nil, row)
266
- task_token = Token.new(row[:id])
267
- task = AcquiredTask.new(@client, row[:id], attributes, task_token)
268
- tasks.push task
269
- }
270
- @cleanup_interval_count -= 1
271
-
272
- return tasks
273
- }
274
- ensure
275
- STDERR.puts "PQ:acquire from #{@table}:%6f sec (%d tasks)" % [Process.clock_gettime(Process::CLOCK_MONOTONIC)-t0,tasks.size] if tasks
206
+ if @disable_resource_limit
207
+ return acquire_without_resource(next_timeout, now, max_acquire)
208
+ else
209
+ return acquire_with_resource(next_timeout, now, max_acquire)
210
+ end
276
211
  end
277
212
 
278
213
  def force_finish(key, retention_time, options)
@@ -454,7 +389,98 @@ SQL
454
389
  }
455
390
  end
456
391
 
392
+ def acquire_without_resource(next_timeout, now, max_acquire)
393
+ # MySQL's CONNECTION_ID() is a 64bit unsigned integer from the
394
+ # server's internal thread ID counter. It is unique while the MySQL
395
+ # server is running.
396
+ # https://bugs.mysql.com/bug.php?id=19806
397
+ #
398
+ # An acquired task is marked with next_timeout and CONNECTION_ID().
399
+ # Therefore while alive_time is not changed and we don't restart
400
+ # the server in 1 second, they won't conflict.
401
+ update_sql = <<SQL
402
+ UPDATE `#{@table}`
403
+ JOIN (
404
+ SELECT id
405
+ FROM `#{@table}` FORCE INDEX (`index_#{@table}_on_timeout`)
406
+ WHERE #{EVENT_HORIZON} < timeout AND timeout <= :now
407
+ ORDER BY timeout ASC
408
+ LIMIT :max_acquire) AS t1 USING(id)
409
+ SET timeout=:next_timeout, owner=CONNECTION_ID()
410
+ SQL
411
+ select_sql = <<SQL
412
+ SELECT id, timeout, data, created_at, resource
413
+ FROM `#{@table}`
414
+ WHERE timeout = ? AND owner = CONNECTION_ID()
415
+ SQL
416
+ t0 = 0
417
+ connect_locked do
418
+ t0 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
419
+ n = @db[update_sql, next_timeout: next_timeout, now: now, max_acquire: max_acquire].update
420
+ @table_unlock.call
421
+ STDERR.puts "PQ:acquire from #{@table}:%6f sec (%d tasks)" % [Process.clock_gettime(Process::CLOCK_MONOTONIC)-t0,n]
422
+ return nil if n <= 0
423
+
424
+ tasks = []
425
+ @db.fetch(select_sql, next_timeout) do |row|
426
+ attributes = create_attributes(nil, row)
427
+ task_token = Token.new(row[:id])
428
+ task = AcquiredTask.new(@client, row[:id], attributes, task_token)
429
+ tasks.push task
430
+ end
431
+ @cleanup_interval_count -= 1
432
+ return tasks
433
+ end
434
+ end
435
+
436
+ def acquire_with_resource(next_timeout, now, max_acquire)
437
+ t0 = nil
438
+ tasks = nil
439
+ sql = <<SQL
440
+ SELECT id, timeout, data, created_at, resource, max_running, IFNULL(max_running, 1) / (IFNULL(running, 0) + 1) AS weight
441
+ FROM `#{@table}`
442
+ LEFT JOIN (
443
+ SELECT resource AS res, COUNT(1) AS running
444
+ FROM `#{@table}` AS T
445
+ WHERE timeout > ? AND created_at IS NOT NULL AND resource IS NOT NULL
446
+ GROUP BY resource
447
+ ) AS R ON resource = res
448
+ WHERE #{EVENT_HORIZON} < timeout AND timeout <= ?
449
+ AND created_at IS NOT NULL
450
+ AND (max_running-running IS NULL OR max_running-running > 0)
451
+ ORDER BY weight DESC, timeout ASC
452
+ LIMIT ?
453
+ SQL
454
+ connect_locked do
455
+ t0 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
456
+ tasks = []
457
+ @db.fetch(sql, now, now, max_acquire) do |row|
458
+ attributes = create_attributes(nil, row)
459
+ task_token = Token.new(row[:id])
460
+ task = AcquiredTask.new(@client, row[:id], attributes, task_token)
461
+ tasks.push task
462
+ end
463
+ return nil if tasks.empty?
464
+
465
+ sql = "UPDATE `#{@table}` FORCE INDEX (PRIMARY) SET timeout=? WHERE timeout <= ? AND id IN ("
466
+ params = [sql, next_timeout, now]
467
+ params.concat tasks.map(&:key)
468
+ sql << '?,' * tasks.size
469
+ sql.chop!
470
+ sql << ") AND created_at IS NOT NULL"
471
+
472
+ n = @db[*params].update
473
+ if n != tasks.size
474
+ # preempted
475
+ return nil
476
+ end
477
+ end
478
+ @cleanup_interval_count -= 1
479
+ return tasks
480
+ ensure
481
+ STDERR.puts "PQ:acquire from #{@table}:%6f sec (%d tasks)" % \
482
+ [Process.clock_gettime(Process::CLOCK_MONOTONIC)-t0, tasks.size] if tasks
483
+ end
457
484
  end
458
485
  end
459
486
  end
460
-
@@ -1,3 +1,3 @@
1
1
  module PerfectQueue
2
- VERSION = "0.9.1"
2
+ VERSION = "0.9.2"
3
3
  end
@@ -96,7 +96,7 @@ describe Backend::RDBCompatBackend do
96
96
  end
97
97
  it 'supports mysql' do
98
98
  expect(Backend::RDBCompatBackend.new(client, config)).to be_an_instance_of(Backend::RDBCompatBackend)
99
- expect(db.instance_variable_get(:@sql)).to include('max_running')
99
+ expect(db.instance_variable_get(:@disable_resource_limit)).to be_falsey
100
100
  end
101
101
  it 'doesn\'t support postgres' do
102
102
  config = {url: 'postgres://localhost', table: table}
@@ -110,7 +110,7 @@ describe Backend::RDBCompatBackend do
110
110
  it 'disable_resource_limit' do
111
111
  config = {url: 'mysql2://root:@localhost/perfectqueue_test', table: table, disable_resource_limit: true}
112
112
  db = Backend::RDBCompatBackend.new(client, config)
113
- expect(db.instance_variable_get(:@sql)).not_to include('max_running')
113
+ expect(db.instance_variable_get(:@disable_resource_limit)).to be_truthy
114
114
  end
115
115
  end
116
116
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: perfectqueue
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.1
4
+ version: 0.9.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sadayuki Furuhashi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-09-23 00:00:00.000000000 Z
11
+ date: 2016-10-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sequel