ione 1.2.0.pre4 → 1.2.0.pre5

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: b0d198d610290a10e580f755f216bbae8ccca0ab
4
- data.tar.gz: ada926b95e4a03d55ffad99687ca9f468d1cdd1f
3
+ metadata.gz: c9338bdefe6cebb6528e884eed99230b3bd6ef0c
4
+ data.tar.gz: 3e28ef46473409fcca687711a9550a4c91539d67
5
5
  SHA512:
6
- metadata.gz: 85e98209e280e3fcd0ca52577ffde6fdbe337191af45830bf9b43d3ded0839aa3ef902267da22abb62f937a2d3321ca0abaf15cd66a0920dfe2a9dc3357d2f19
7
- data.tar.gz: e5eac3de0c0024e20bad63f82a32a57973d50081df75bf789f7d76bfda413bb8a180bb5ae6919be3aff91c4fa809d8596bfa26a02b0f3bc995b023801cbf3133
6
+ metadata.gz: 2f28bebc52bf02a2d885d611b26cb68204e026e35c16d29790b320dc936adfa1e8af2f495148910696df8d7f9c5fc4346115424e3dd82ad52506193daf4ace9e
7
+ data.tar.gz: 5a466d53f3988533504292269b7494e993ad955be605eccbd9d7230ec2c238fbcb276290a6dc465eaedc6d51e49c814c610304bbb61900048fd45206452ef64a
data/lib/ione/heap.rb ADDED
@@ -0,0 +1,92 @@
1
+ # encoding: utf-8
2
+
3
+ module Ione
4
+ # @private
5
+ class Heap
6
+ def initialize
7
+ @items = []
8
+ end
9
+
10
+ def size
11
+ @items.size
12
+ end
13
+
14
+ def empty?
15
+ @items.empty?
16
+ end
17
+
18
+ def push(item)
19
+ @items << item
20
+ bubble_up(@items.size - 1)
21
+ end
22
+ alias_method :<<, :push
23
+
24
+ def peek
25
+ @items.first
26
+ end
27
+
28
+ def pop
29
+ if @items.size == 0
30
+ nil
31
+ elsif @items.size == 1
32
+ @items.pop
33
+ else
34
+ item = @items.first
35
+ @items[0] = @items.pop
36
+ bubble_down(0)
37
+ item
38
+ end
39
+ end
40
+
41
+ def delete(item)
42
+ if item == @items[0]
43
+ pop
44
+ elsif (i = index(item))
45
+ item = @items[i]
46
+ @items[i] = @items.pop
47
+ bubble_down(i)
48
+ item
49
+ end
50
+ end
51
+
52
+ private
53
+
54
+ def index(item, root_index=0)
55
+ left_index = (root_index * 2) + 1
56
+ right_index = (root_index * 2) + 2
57
+ root_item = @items[root_index]
58
+ if root_item == item
59
+ root_index
60
+ elsif left_index < @items.length && item >= @items[left_index] && (i = index(item, left_index))
61
+ i
62
+ elsif right_index < @items.length && item >= @items[right_index] && (i = index(item, right_index))
63
+ i
64
+ end
65
+ end
66
+
67
+ def bubble_up(index)
68
+ parent_index = (index - 1)/2
69
+ if parent_index >= 0 && @items[parent_index] > @items[index]
70
+ item = @items[index]
71
+ @items[index] = @items[parent_index]
72
+ @items[parent_index] = item
73
+ bubble_up(parent_index)
74
+ end
75
+ end
76
+
77
+ def bubble_down(index)
78
+ child_index = (index * 2) + 1
79
+ unless child_index >= @items.length
80
+ if child_index + 1 < @items.length && @items[child_index] > @items[child_index + 1]
81
+ child_index += 1
82
+ end
83
+ if @items[index] > @items[child_index]
84
+ item = @items[index]
85
+ @items[index] = @items[child_index]
86
+ @items[child_index] = item
87
+ bubble_down(child_index)
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
@@ -1,5 +1,8 @@
1
1
  # encoding: utf-8
2
2
 
3
+ require 'ione/heap'
4
+
5
+
3
6
  module Ione
4
7
  module Io
5
8
  ReactorError = Class.new(IoError)
@@ -298,6 +301,32 @@ module Ione
298
301
  DEFAULT_CONNECT_OPTIONS = {:timeout => 5}.freeze
299
302
  end
300
303
 
304
+ # @private
305
+ class Timer < Promise
306
+ include Comparable
307
+
308
+ attr_reader :time
309
+
310
+ def initialize(time)
311
+ super()
312
+ @time = time
313
+ end
314
+
315
+ def <=>(other)
316
+ cmp = @time <=> other.time
317
+ if cmp == 0
318
+ self.object_id <=> other.object_id
319
+ else
320
+ cmp
321
+ end
322
+ end
323
+
324
+ def to_s
325
+ "#<Timer #{@time}>"
326
+ end
327
+ alias_method :inspect, :to_s
328
+ end
329
+
301
330
  # @private
302
331
  class IoLoopBody
303
332
  def initialize(options={})
@@ -305,7 +334,8 @@ module Ione
305
334
  @clock = options[:clock] || Time
306
335
  @lock = Mutex.new
307
336
  @sockets = []
308
- @timers = []
337
+ @timer_queue = Heap.new
338
+ @pending_timers = {}
309
339
  end
310
340
 
311
341
  def add_socket(socket)
@@ -323,24 +353,29 @@ module Ione
323
353
  end
324
354
  end
325
355
 
326
- def schedule_timer(timeout, promise=Promise.new)
356
+ def schedule_timer(timeout)
327
357
  @lock.lock
328
- timers = @timers.reject { |pair| pair[1].nil? }
329
- timers << [@clock.now + timeout, promise]
330
- @timers = timers
331
- promise.future
358
+ timer = Timer.new(@clock.now + timeout)
359
+ @timer_queue << timer
360
+ @pending_timers[timer.future] = timer
361
+ timer.future
332
362
  ensure
333
363
  @lock.unlock
334
364
  end
335
365
 
336
366
  def cancel_timer(timer_future)
367
+ timer = nil
337
368
  @lock.lock
338
- timer_pair = @timers.find { |pair| (p = pair[1]) && p.future == timer_future }
339
- @timers = @timers.reject { |pair| pair[1].nil? || pair == timer_pair }
340
- timer_pair && timer_pair[1].fail(CancelledError.new)
341
- nil
342
- ensure
343
- @lock.unlock
369
+ begin
370
+ if (timer = @pending_timers.delete(timer_future))
371
+ @timer_queue.delete(timer)
372
+ end
373
+ ensure
374
+ @lock.unlock
375
+ end
376
+ if timer
377
+ timer.fail(CancelledError.new)
378
+ end
344
379
  end
345
380
 
346
381
  def close_sockets
@@ -354,11 +389,9 @@ module Ione
354
389
  end
355
390
 
356
391
  def cancel_timers
357
- @timers.each do |pair|
358
- if pair[1]
359
- pair[1].fail(CancelledError.new)
360
- pair[1] = nil
361
- end
392
+ while (timer = @timer_queue.pop)
393
+ @pending_timers.delete(timer.future)
394
+ timer.fail(CancelledError.new)
362
395
  end
363
396
  end
364
397
 
@@ -392,11 +425,22 @@ module Ione
392
425
  end
393
426
 
394
427
  def check_timers!
395
- timers = @timers
396
- timers.each do |pair|
397
- if pair[1] && pair[0] <= @clock.now
398
- pair[1].fulfill
399
- pair[1] = nil
428
+ now = @clock.now
429
+ first_timer = @timer_queue.peek
430
+ if first_timer && first_timer.time <= now
431
+ expired_timers = []
432
+ @lock.lock
433
+ begin
434
+ while (timer = @timer_queue.peek) && timer.time <= now
435
+ @timer_queue.pop
436
+ @pending_timers.delete(timer.future)
437
+ expired_timers << timer
438
+ end
439
+ ensure
440
+ @lock.unlock
441
+ end
442
+ expired_timers.each do |timer|
443
+ timer.fulfill
400
444
  end
401
445
  end
402
446
  end
data/lib/ione/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module Ione
4
- VERSION = '1.2.0.pre4'.freeze
4
+ VERSION = '1.2.0.pre5'.freeze
5
5
  end
@@ -0,0 +1,160 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+
6
+ module Ione
7
+ describe Heap do
8
+ let :heap do
9
+ described_class.new
10
+ end
11
+
12
+ describe '#size' do
13
+ it 'is zero when the heap is empty' do
14
+ heap.size.should be_zero
15
+ end
16
+
17
+ it 'returns the number of items in the heap' do
18
+ heap.push(13)
19
+ heap.push(100)
20
+ heap.size.should == 2
21
+ heap.push(101)
22
+ heap.size.should == 3
23
+ end
24
+ end
25
+
26
+ describe '#empty?' do
27
+ it 'returns true when there are no items in the heap' do
28
+ heap.should be_empty
29
+ end
30
+
31
+ it 'returns false when there are items in the heap' do
32
+ heap.push(1)
33
+ heap.should_not be_empty
34
+ end
35
+ end
36
+
37
+ describe '#push' do
38
+ it 'adds items to the heap' do
39
+ heap.push(4)
40
+ heap.push(3)
41
+ heap.push(6)
42
+ heap.push(5)
43
+ heap.size.should == 4
44
+ end
45
+
46
+ it 'is aliase as #<<' do
47
+ heap << 4
48
+ heap << 3
49
+ heap << 6
50
+ heap << 5
51
+ heap.size.should == 4
52
+ end
53
+ end
54
+
55
+ describe '#peek' do
56
+ it 'returns nil when there are no items in the heap' do
57
+ heap.peek.should be_nil
58
+ end
59
+
60
+ it 'returns the only item when there is only one' do
61
+ heap.push(3)
62
+ heap.peek.should == 3
63
+ end
64
+
65
+ it 'returns the smallest item' do
66
+ heap.push(10)
67
+ heap.push(3)
68
+ heap.push(7)
69
+ heap.peek.should == 3
70
+ end
71
+
72
+ it 'does not remove the item from the heap' do
73
+ heap.push(3)
74
+ heap.peek.should == 3
75
+ heap.peek.should == 3
76
+ heap.peek.should == 3
77
+ end
78
+ end
79
+
80
+ describe '#pop' do
81
+ it 'returns nil when there are no items in the heap' do
82
+ heap.pop.should be_nil
83
+ end
84
+
85
+ it 'returns and removes the only item when there is only one' do
86
+ heap.push(3)
87
+ heap.pop.should == 3
88
+ heap.should be_empty
89
+ end
90
+
91
+ it 'returns and removes the smallest item' do
92
+ heap.push(10)
93
+ heap.push(3)
94
+ heap.push(7)
95
+ heap.pop.should == 3
96
+ heap.pop.should == 7
97
+ heap.size.should == 1
98
+ end
99
+
100
+ it 'removes the item from the heap' do
101
+ heap.push(3)
102
+ heap.pop.should == 3
103
+ heap.pop.should be_nil
104
+ end
105
+
106
+ it 'returns each duplicate' do
107
+ heap.push(3)
108
+ heap.push(4)
109
+ heap.push(3)
110
+ heap.push(3)
111
+ heap.pop.should == 3
112
+ heap.pop.should == 3
113
+ heap.pop.should == 3
114
+ heap.pop.should == 4
115
+ end
116
+ end
117
+
118
+ describe '#delete' do
119
+ it 'removes the item from a heap with one item' do
120
+ heap.push(3)
121
+ heap.delete(3)
122
+ heap.should be_empty
123
+ end
124
+
125
+ it 'removes the item from the heap' do
126
+ heap.push(4)
127
+ heap.push(3)
128
+ heap.push(100)
129
+ heap.push(101)
130
+ heap.delete(4)
131
+ heap.pop
132
+ heap.peek.should == 100
133
+ heap.size.should == 2
134
+ end
135
+
136
+ it 'returns the item' do
137
+ heap.push(3)
138
+ heap.push(4)
139
+ heap.push(5)
140
+ heap.delete(4).should == 4
141
+ end
142
+
143
+ it 'returns nil when the item is not found' do
144
+ heap.push(3)
145
+ heap.push(4)
146
+ heap.push(5)
147
+ heap.delete(6).should be_nil
148
+ end
149
+
150
+ it 'removes the first instance of the item from the heap' do
151
+ heap.push(3)
152
+ heap.push(3)
153
+ heap.push(5)
154
+ heap.delete(3).should == 3
155
+ heap.delete(3).should == 3
156
+ heap.size.should == 1
157
+ end
158
+ end
159
+ end
160
+ end
@@ -435,25 +435,22 @@ module Ione
435
435
  it 'completes timers that have expired' do
436
436
  selector.stub(:select).and_return([nil, nil, nil])
437
437
  clock.stub(:now).and_return(1)
438
- promise = Promise.new
439
- loop_body.schedule_timer(1, promise)
438
+ future = loop_body.schedule_timer(1)
440
439
  loop_body.tick
441
- promise.future.should_not be_completed
440
+ future.should_not be_completed
442
441
  clock.stub(:now).and_return(2)
443
442
  loop_body.tick
444
- promise.future.should be_completed
443
+ future.should be_completed
445
444
  end
446
445
 
447
446
  it 'clears out timers that have expired' do
448
447
  selector.stub(:select).and_return([nil, nil, nil])
449
448
  clock.stub(:now).and_return(1)
450
- promise = Promise.new
451
- loop_body.schedule_timer(1, promise)
449
+ future = loop_body.schedule_timer(1)
452
450
  clock.stub(:now).and_return(2)
453
451
  loop_body.tick
454
- promise.future.should be_completed
455
- promise.should_not_receive(:fulfill)
456
- loop_body.tick
452
+ future.should be_completed
453
+ expect { loop_body.tick }.to_not raise_error
457
454
  end
458
455
  end
459
456
 
@@ -492,20 +489,17 @@ module Ione
492
489
  end
493
490
 
494
491
  it 'fails all active timers with a CancelledError' do
495
- p1 = Promise.new
496
- p2 = Promise.new
497
- p3 = Promise.new
498
492
  clock.stub(:now).and_return(1)
499
- loop_body.schedule_timer(1, p1)
500
- loop_body.schedule_timer(3, p2)
501
- loop_body.schedule_timer(3, p3)
493
+ f1 = loop_body.schedule_timer(1)
494
+ f2 = loop_body.schedule_timer(3)
495
+ f3 = loop_body.schedule_timer(3)
502
496
  clock.stub(:now).and_return(2)
503
497
  loop_body.tick
504
498
  loop_body.cancel_timers
505
- p1.future.should be_completed
506
- p2.future.should be_failed
507
- p3.future.should be_failed
508
- expect { p3.future.value }.to raise_error(CancelledError)
499
+ f1.should be_completed
500
+ f2.should be_failed
501
+ f3.should be_failed
502
+ expect { f3.value }.to raise_error(CancelledError)
509
503
  end
510
504
  end
511
505
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ione
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0.pre4
4
+ version: 1.2.0.pre5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Theo Hultberg
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-09-24 00:00:00.000000000 Z
11
+ date: 2014-10-26 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Reactive programming framework for Ruby, painless evented IO, futures
14
14
  and an efficient byte buffer
@@ -23,6 +23,7 @@ files:
23
23
  - lib/ione.rb
24
24
  - lib/ione/byte_buffer.rb
25
25
  - lib/ione/future.rb
26
+ - lib/ione/heap.rb
26
27
  - lib/ione/io.rb
27
28
  - lib/ione/io/acceptor.rb
28
29
  - lib/ione/io/base_connection.rb
@@ -37,6 +38,7 @@ files:
37
38
  - spec/integration/ssl_spec.rb
38
39
  - spec/ione/byte_buffer_spec.rb
39
40
  - spec/ione/future_spec.rb
41
+ - spec/ione/heap_spec.rb
40
42
  - spec/ione/io/acceptor_spec.rb
41
43
  - spec/ione/io/connection_common.rb
42
44
  - spec/ione/io/connection_spec.rb
@@ -77,6 +79,7 @@ test_files:
77
79
  - spec/integration/ssl_spec.rb
78
80
  - spec/ione/byte_buffer_spec.rb
79
81
  - spec/ione/future_spec.rb
82
+ - spec/ione/heap_spec.rb
80
83
  - spec/ione/io/acceptor_spec.rb
81
84
  - spec/ione/io/connection_common.rb
82
85
  - spec/ione/io/connection_spec.rb