perfectqueue 0.9.1 → 0.9.2

Sign up to get free protection for your applications and to get access to all the features.
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