amq-protocol 1.0.0.pre2 → 1.0.0.pre3

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.
@@ -0,0 +1,96 @@
1
+ # encoding: utf-8
2
+
3
+ require "amq/bit_set"
4
+
5
+ module AMQ
6
+ # Simple bitset-based integer allocator, heavily inspired by com.rabbitmq.utility.IntAllocator class
7
+ # in the RabbitMQ Java client.
8
+ #
9
+ # Unlike monotonically incrementing identifier, this allocator is suitable for very long running programs
10
+ # that aggressively allocate and release channels.
11
+ class IntAllocator
12
+
13
+ #
14
+ # API
15
+ #
16
+
17
+ # @return [Integer] Number of integers in the allocation range
18
+ attr_reader :number_of_bits
19
+ # @return [Integer] Upper boundary of the integer range available for allocation
20
+ attr_reader :hi
21
+ # @return [Integer] Lower boundary of the integer range available for allocation
22
+ attr_reader :lo
23
+
24
+ # @param [Integer] lo Lower boundary of the integer range available for allocation
25
+ # @param [Integer] hi Upper boundary of the integer range available for allocation
26
+ # @raise [ArgumentError] if upper boundary is not greater than the lower one
27
+ def initialize(lo, hi)
28
+ raise ArgumentError.new "upper boundary must be greater than the lower one (given: hi = #{hi}, lo = #{lo})" unless hi > lo
29
+
30
+ @hi = hi
31
+ @lo = lo
32
+
33
+ @number_of_bits = hi - lo
34
+ @range = Range.new(1, @number_of_bits)
35
+ @free_set = BitSet.new(@number_of_bits)
36
+ end # initialize(hi, lo)
37
+
38
+ # Attempts to allocate next available integer. If allocation succeeds, allocated value is returned.
39
+ # Otherwise, nil is returned.
40
+ #
41
+ # Current implementation of this method is O(n), where n is number of bits in the range available for
42
+ # allocation.
43
+ #
44
+ # @return [Integer] Allocated integer if allocation succeeded. nil otherwise.
45
+ def allocate
46
+ if n = find_unallocated_position
47
+ @free_set.set(n)
48
+
49
+ n
50
+ else
51
+ -1
52
+ end
53
+ end # allocate
54
+
55
+ # Releases previously allocated integer. If integer provided as argument was not previously allocated,
56
+ # this method has no effect.
57
+ #
58
+ # @return [NilClass] nil
59
+ def free(reservation)
60
+ @free_set.unset(reservation)
61
+ end # free(reservation)
62
+ alias release free
63
+
64
+ # @return [Boolean] true if provided argument was previously allocated, false otherwise
65
+ def allocated?(reservation)
66
+ @free_set.get(reservation)
67
+ end # allocated?(reservation)
68
+
69
+ # Releases the whole allocation range
70
+ def reset
71
+ @free_set.clear
72
+ end # reset
73
+
74
+
75
+
76
+ protected
77
+
78
+ # This implementation is significantly less efficient
79
+ # that what the RabbitMQ Java client has (based on java.lang.Long#nextSetBit and
80
+ # java.lang.Long.numberOfTrailingZeros, and thus binary search over bits).
81
+ # But for channel id generation, this is a good enough implementation.
82
+ #
83
+ # @private
84
+ def find_unallocated_position
85
+ r = nil
86
+ @range.each do |i|
87
+ if !@free_set.get(i)
88
+ r = i
89
+ break;
90
+ end
91
+ end
92
+
93
+ r
94
+ end # find_unallocated_position
95
+ end # IntAllocator
96
+ end # AMQ
@@ -1,5 +1,5 @@
1
1
  module AMQ
2
2
  module Protocol
3
- VERSION = "1.0.0.pre2"
3
+ VERSION = "1.0.0.pre3"
4
4
  end # Protocol
5
5
  end # AMQ
@@ -0,0 +1,116 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+ require "amq/int_allocator"
5
+
6
+ describe AMQ::IntAllocator do
7
+
8
+ #
9
+ # Environment
10
+ #
11
+
12
+ subject do
13
+ described_class.new(1, 5)
14
+ end
15
+
16
+
17
+ # ...
18
+
19
+
20
+ #
21
+ # Examples
22
+ #
23
+
24
+ describe "#number_of_bits" do
25
+ it "returns number of bits available for allocation" do
26
+ subject.number_of_bits.should == 4
27
+ end
28
+ end
29
+
30
+
31
+ describe "#hi" do
32
+ it "returns upper bound of the allocation range" do
33
+ subject.hi.should == 5
34
+ end
35
+ end
36
+
37
+ describe "#lo" do
38
+ it "returns lower bound of the allocation range" do
39
+ subject.lo.should == 1
40
+ end
41
+ end
42
+
43
+
44
+ describe "#allocate" do
45
+ context "when integer in the range is available" do
46
+ it "returns allocated integer" do
47
+ subject.allocate.should == 1
48
+ subject.allocate.should == 2
49
+ subject.allocate.should == 3
50
+ subject.allocate.should == 4
51
+
52
+ subject.allocate.should == -1
53
+ end
54
+ end
55
+
56
+ context "when integer in the range IS NOT available" do
57
+ it "returns -1" do
58
+ 4.times { subject.allocate }
59
+
60
+ subject.allocate.should == -1
61
+ subject.allocate.should == -1
62
+ subject.allocate.should == -1
63
+ subject.allocate.should == -1
64
+ end
65
+ end
66
+ end
67
+
68
+
69
+ describe "#free" do
70
+ context "when the integer WAS allocated" do
71
+ it "returns frees that integer" do
72
+ 4.times { subject.allocate }
73
+ subject.allocate.should == -1
74
+
75
+ subject.free(1)
76
+ subject.allocate.should == 1
77
+ subject.allocate.should == -1
78
+ subject.free(2)
79
+ subject.allocate.should == 2
80
+ subject.allocate.should == -1
81
+ subject.free(3)
82
+ subject.allocate.should == 3
83
+ subject.allocate.should == -1
84
+ end
85
+ end
86
+
87
+ context "when the integer WAS NOT allocated" do
88
+ it "has no effect" do
89
+ 32.times { subject.free(1) }
90
+ subject.allocate.should == 1
91
+ end
92
+ end
93
+ end
94
+
95
+
96
+ describe "#allocated?" do
97
+ context "when given position WAS allocated" do
98
+ it "returns true" do
99
+ 3.times { subject.allocate }
100
+
101
+ subject.allocated?(1).should be_true
102
+ subject.allocated?(2).should be_true
103
+ subject.allocated?(3).should be_true
104
+ end
105
+ end
106
+
107
+ context "when given position WAS NOT allocated" do
108
+ it "returns false" do
109
+ 2.times { subject.allocate }
110
+
111
+ subject.allocated?(3).should be_false
112
+ subject.allocated?(4).should be_false
113
+ end
114
+ end
115
+ end
116
+ end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: amq-protocol
3
3
  version: !ruby/object:Gem::Version
4
- hash: -2170921152
4
+ hash: 4271866905
5
5
  prerelease: 6
6
6
  segments:
7
7
  - 1
8
8
  - 0
9
9
  - 0
10
10
  - pre
11
- - 2
12
- version: 1.0.0.pre2
11
+ - 3
12
+ version: 1.0.0.pre3
13
13
  platform: ruby
14
14
  authors:
15
15
  - Jakub Stastny
@@ -51,6 +51,7 @@ files:
51
51
  - irb.rb
52
52
  - lib/amq/bit_set.rb
53
53
  - lib/amq/hacks.rb
54
+ - lib/amq/int_allocator.rb
54
55
  - lib/amq/protocol.rb
55
56
  - lib/amq/protocol/client.rb
56
57
  - lib/amq/protocol/frame.rb
@@ -63,6 +64,7 @@ files:
63
64
  - protocol.rb.pytemplate
64
65
  - spec/amq/bit_set_spec.rb
65
66
  - spec/amq/hacks_spec.rb
67
+ - spec/amq/int_allocator_spec.rb
66
68
  - spec/amq/protocol/basic_spec.rb
67
69
  - spec/amq/protocol/blank_body_encoding_spec.rb
68
70
  - spec/amq/protocol/channel_spec.rb