amq-protocol 1.8.0 → 1.9.0

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: 4ed555f9528be0395d8ba9a11a39e193aa347f89
4
- data.tar.gz: 345f66cb02153603fb16465bc9edddaf1b2bc63a
3
+ metadata.gz: 4ac3c4778d62f3a7f84cd1132c77de339a2e97c3
4
+ data.tar.gz: 205cf9a34ea9addcfe2458e1dfcc9b6fe8a6c81c
5
5
  SHA512:
6
- metadata.gz: b5b11714e11f26704f9768d750bb61c4034edac91141d6a1743ad7fbbc6999fc88b2c70acbbbc42f14cdc6bd3eb3a0a3441519bd2922413a03d13a208d101e08
7
- data.tar.gz: f50280bc01e330a2b2952585b444ceb5b195855836d572791c727c73b6d295b3037b76fc4ccf042837656a684f23889658114a981a55a33f50a05651d85b8478
6
+ metadata.gz: ed02a18089fc8e1f633716981a1d995cf5ad6eb8663bdfb794effc32351dea6d97b56cbcea01a413f65d1ace0a56f1853bbe0bcce10072587c9439eb60d748d2
7
+ data.tar.gz: 0c2344d1e5919666c6b38934fe3f38817f117f117ed8606b6090c96e7e43c6e8afa556bbf4bf9e2e082e7bea75518ac5090f9d48d869525edb532fc67a95856e
@@ -6,14 +6,12 @@ rvm:
6
6
  - 1.9.3
7
7
  - jruby-19mode
8
8
  - 1.9.2
9
- - rbx-19mode
9
+ - rbx-2.2.0
10
10
  - ruby-head
11
- - jruby-head
12
11
  - 1.8.7
13
- - rbx-18mode
14
12
  notifications:
15
13
  recipients:
16
- - michael@novemberain.com
14
+ - michael@rabbitmq.com
17
15
  matrix:
18
16
  allow_failures:
19
17
  - rvm: ruby-head
@@ -1,3 +1,23 @@
1
+ ## Changes between 1.8.0 and 1.9.0
2
+
3
+ ### Performance Improvements in AMQ::BitSet
4
+
5
+ `AMQ::BitSet#next_clear_bit` is now drastically more efficient
6
+ (down from 6 minutes for 10,000 iterations to 4 seconds for 65,536 iterations).
7
+
8
+ Contributed by Doug Rohrer, Dave Anderson, and Jason Voegele from
9
+ [Neo](http://www.neo.com).
10
+
11
+
12
+ ## Changes between 1.7.0 and 1.8.0
13
+
14
+ ### Body Framing Fix
15
+
16
+ Messages exactly 128 Kb in size are now framed correctly.
17
+
18
+ Contributed by Nicolas Viennot.
19
+
20
+
1
21
  ## Changes between 1.6.0 and 1.7.0
2
22
 
3
23
  ### connection.blocked Support
data/README.md CHANGED
@@ -43,7 +43,7 @@ amq-protocol is maintained by [Michael Klishin](https://github.com/michaelklishi
43
43
  [![Build Status](https://secure.travis-ci.org/ruby-amqp/amq-protocol.png)](https://travis-ci.org/ruby-amqp/amq-protocol)
44
44
 
45
45
 
46
- ## Development
46
+ ## Issues
47
47
 
48
48
  Please report any issues you may find to our [Issue tracker](http://github.com/ruby-amqp/amq-protocol/issues) on GitHub.
49
49
 
@@ -0,0 +1,34 @@
1
+ $LOAD_PATH << File.expand_path(File.join(File.dirname(__FILE__), "..", "lib"))
2
+
3
+ require 'amq/int_allocator'
4
+ require "benchmark"
5
+
6
+ allocator = AMQ::IntAllocator.new(1,65535)
7
+ mutex = Mutex.new
8
+
9
+ Benchmark.bm do |x|
10
+
11
+
12
+ x.report("allocate") do
13
+ allocator = AMQ::IntAllocator.new(1,65535)
14
+ 1.upto(65534) do |i|
15
+ mutex.synchronize do
16
+ n = allocator.allocate
17
+ raise 'it be broke' unless n == i
18
+ end
19
+ end
20
+ end
21
+
22
+ x.report("allocate_with_release") do
23
+ allocator = AMQ::IntAllocator.new(1,65535)
24
+ 1.upto(65534) do |i|
25
+ mutex.synchronize do
26
+ n = allocator.allocate
27
+ if i % 5 == 0
28
+ allocator.release(n)
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ end
@@ -7,6 +7,7 @@ module AMQ
7
7
  # Originally part of amqp gem. Extracted to make it possible for Bunny to use it.
8
8
  class BitSet
9
9
 
10
+ attr_reader :words_in_use
10
11
  #
11
12
  # API
12
13
  #
@@ -28,8 +29,10 @@ module AMQ
28
29
  # @param [Integer] A bit to set
29
30
  # @api public
30
31
  def set(i)
32
+ check_range(i)
31
33
  w = self.word_index(i)
32
- @words[w] |= (1 << i)
34
+ result = @words[w] |= (1 << (i % BITS_PER_WORD))
35
+ result
33
36
  end # set(i)
34
37
 
35
38
  # Fetches flag value for given bit.
@@ -38,9 +41,10 @@ module AMQ
38
41
  # @return [Boolean] true if given bit is set, false otherwise
39
42
  # @api public
40
43
  def get(i)
44
+ check_range(i)
41
45
  w = self.word_index(i)
42
46
 
43
- (@words[w] & (1 << i)) != 0
47
+ (@words[w] & (1 << i % BITS_PER_WORD)) != 0
44
48
  end # get(i)
45
49
  alias [] get
46
50
 
@@ -49,10 +53,12 @@ module AMQ
49
53
  # @param [Integer] A bit to unset
50
54
  # @api public
51
55
  def unset(i)
56
+ check_range(i)
52
57
  w = self.word_index(i)
53
58
  return if w.nil?
54
59
 
55
- @words[w] &= ~(1 << i)
60
+ result = @words[w] &= ~(1 << i % BITS_PER_WORD)
61
+ result
56
62
  end # unset(i)
57
63
 
58
64
  # Clears all bits in the set
@@ -61,22 +67,53 @@ module AMQ
61
67
  self.init_words(@nbits)
62
68
  end # clear
63
69
 
70
+ def next_clear_bit()
71
+ @words.each_with_index do |word, i|
72
+ if word == WORD_MASK
73
+ next
74
+ end
75
+ return i * BITS_PER_WORD + BitSet.number_of_trailing_ones(word)
76
+ end
77
+ -1
78
+ end # next_clear_bit
79
+
80
+ def to_s
81
+ result = ""
82
+ @words.each do |w|
83
+ result += w.to_s(2).rjust(BITS_PER_WORD,'0') + ":"
84
+ end
85
+ result
86
+ end # to_s
64
87
 
65
88
  #
66
89
  # Implementation
67
90
  #
68
91
 
92
+ # @private
93
+ def self.number_of_trailing_ones(num)
94
+ 0.upto(BITS_PER_WORD) do |bit|
95
+ return bit if num[bit] == 0
96
+ end
97
+ BITS_PER_WORD
98
+ end # number_of_trailing_ones
99
+
100
+ # @private
101
+ def word_index(i)
102
+ i >> ADDRESS_BITS_PER_WORD
103
+ end # word_index
104
+
69
105
  protected
70
106
 
71
107
  # @private
72
108
  def init_words(nbits)
73
109
  n = word_index(nbits-1) + 1
74
- @words = Array.new(n) { 1 }
110
+ @words = Array.new(n) { 0 }
75
111
  end # init_words
76
112
 
77
- # @private
78
- def word_index(i)
79
- i >> ADDRESS_BITS_PER_WORD
80
- end # word_index(i)
113
+ def check_range(i)
114
+ if i < 0 || i >= @nbits
115
+ raise IndexError.new("Cannot access bit #{i} from a BitSet with #{@nbits} bits")
116
+ end
117
+ end # check_range
81
118
  end # BitSet
82
119
  end # AMQ
@@ -43,10 +43,16 @@ module AMQ
43
43
  #
44
44
  # @return [Integer] Allocated integer if allocation succeeded. nil otherwise.
45
45
  def allocate
46
- if n = find_unallocated_position
47
- @free_set.set(n)
48
46
 
49
- n
47
+ if n = @free_set.next_clear_bit
48
+
49
+ if n < @hi - 1 then
50
+ @free_set.set(n)
51
+ n + 1
52
+ else
53
+ -1
54
+ end
55
+
50
56
  else
51
57
  -1
52
58
  end
@@ -57,13 +63,13 @@ module AMQ
57
63
  #
58
64
  # @return [NilClass] nil
59
65
  def free(reservation)
60
- @free_set.unset(reservation)
66
+ @free_set.unset(reservation-1)
61
67
  end # free(reservation)
62
68
  alias release free
63
69
 
64
70
  # @return [Boolean] true if provided argument was previously allocated, false otherwise
65
71
  def allocated?(reservation)
66
- @free_set.get(reservation)
72
+ @free_set.get(reservation-1)
67
73
  end # allocated?(reservation)
68
74
 
69
75
  # Releases the whole allocation range
@@ -75,22 +81,5 @@ module AMQ
75
81
 
76
82
  protected
77
83
 
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
84
  end # IntAllocator
96
85
  end # AMQ
@@ -1,5 +1,5 @@
1
1
  module AMQ
2
2
  module Protocol
3
- VERSION = "1.8.0"
3
+ VERSION = "1.9.0"
4
4
  end # Protocol
5
5
  end # AMQ
@@ -19,6 +19,32 @@ describe AMQ::BitSet do
19
19
  # Examples
20
20
  #
21
21
 
22
+ describe "#new" do
23
+ it "has no bits set at the start" do
24
+ bs = AMQ::BitSet.new(128)
25
+ 0.upto(127) do |i|
26
+ bs[i].should == false
27
+ end
28
+ end # it
29
+ end # describe
30
+
31
+ describe "#word_index" do
32
+ subject do
33
+ described_class.new(nbits)
34
+ end
35
+ it "returns 0 when the word is between 0 and 63" do
36
+ subject.word_index(0).should == 0
37
+ subject.word_index(63).should == 0
38
+ end # it
39
+ it "returns 1 when the word is between 64 and 127" do
40
+ subject.word_index(64).should == 1
41
+ subject.word_index(127).should == 1
42
+ end # it
43
+ it "returns 2 when the word is between 128 and another number" do
44
+ subject.word_index(128).should == 2
45
+ end # it
46
+ end # describe
47
+
22
48
  describe "#get, #[]" do
23
49
  describe "when bit at given position is set" do
24
50
  subject do
@@ -41,6 +67,19 @@ describe AMQ::BitSet do
41
67
  subject.get(5).should be_false
42
68
  end # it
43
69
  end # describe
70
+
71
+ describe "when index out of range" do
72
+ subject do
73
+ described_class.new(nbits)
74
+ end
75
+
76
+ it "should raise IndexError for negative index" do
77
+ lambda { subject.get(-1) }.should raise_error(IndexError)
78
+ end # it
79
+ it "should raise IndexError for index >= number of bits" do
80
+ lambda { subject.get(nbits) }.should raise_error(IndexError)
81
+ end # it
82
+ end # describe
44
83
  end # describe
45
84
 
46
85
 
@@ -56,7 +95,7 @@ describe AMQ::BitSet do
56
95
  subject.set(3)
57
96
  subject[3].should be_true
58
97
  end # it
59
- end
98
+ end # describe
60
99
 
61
100
  describe "when bit at given position is off" do
62
101
  subject do
@@ -72,7 +111,20 @@ describe AMQ::BitSet do
72
111
 
73
112
  subject.set(3387)
74
113
  subject.get(3387).should be_true
114
+ end # it
115
+ end # describe
116
+
117
+ describe "when index out of range" do
118
+ subject do
119
+ described_class.new(nbits)
75
120
  end
121
+
122
+ it "should raise IndexError for negative index" do
123
+ lambda { subject.set(-1) }.should raise_error(IndexError)
124
+ end # it
125
+ it "should raise IndexError for index >= number of bits" do
126
+ lambda { subject.set(nbits) }.should raise_error(IndexError)
127
+ end # it
76
128
  end # describe
77
129
  end # describe
78
130
 
@@ -103,6 +155,19 @@ describe AMQ::BitSet do
103
155
  subject.get(3).should be_false
104
156
  end # it
105
157
  end # describe
158
+
159
+ describe "when index out of range" do
160
+ subject do
161
+ described_class.new(nbits)
162
+ end
163
+
164
+ it "should raise IndexError for negative index" do
165
+ lambda { subject.unset(-1) }.should raise_error(IndexError)
166
+ end # it
167
+ it "should raise IndexError for index >= number of bits" do
168
+ lambda { subject.unset(nbits) }.should raise_error(IndexError)
169
+ end # it
170
+ end # describe
106
171
  end # describe
107
172
 
108
173
 
@@ -123,6 +188,45 @@ describe AMQ::BitSet do
123
188
 
124
189
  subject.get(3).should be_false
125
190
  subject.get(7668).should be_false
191
+ end # it
192
+ end # describe
193
+
194
+ describe "#number_of_trailing_ones" do
195
+ it "calculates them" do
196
+ described_class.number_of_trailing_ones(0).should == 0
197
+ described_class.number_of_trailing_ones(1).should == 1
198
+ described_class.number_of_trailing_ones(2).should == 0
199
+ described_class.number_of_trailing_ones(3).should == 2
200
+ described_class.number_of_trailing_ones(4).should == 0
201
+ end # it
202
+ end # describe
203
+
204
+ describe '#next_clear_bit' do
205
+ subject do
206
+ described_class.new(255)
126
207
  end
127
- end
208
+ it "returns sequential values when none have been returned" do
209
+ subject.next_clear_bit.should == 0
210
+ subject.set(0)
211
+ subject.next_clear_bit.should == 1
212
+ subject.set(1)
213
+ subject.next_clear_bit.should == 2
214
+ subject.unset(1)
215
+ subject.next_clear_bit.should == 1
216
+ end # it
217
+
218
+ it "returns the same number as long as nothing is set" do
219
+ subject.next_clear_bit.should == 0
220
+ subject.next_clear_bit.should == 0
221
+ end # it
222
+
223
+ it "handles more than 128 bits" do
224
+ 0.upto(254) do |i|
225
+ subject.set(i)
226
+ subject.next_clear_bit.should == i + 1
227
+ end
228
+ subject.unset(254)
229
+ subject.get(254).should be_false
230
+ end # it
231
+ end # describe
128
232
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: amq-protocol
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.0
4
+ version: 1.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jakub Stastny
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2013-09-17 00:00:00.000000000 Z
14
+ date: 2013-11-21 00:00:00.000000000 Z
15
15
  dependencies: []
16
16
  description: |2
17
17
  amq-protocol is an AMQP 0.9.1 serialization library for Ruby. It is not an
@@ -35,6 +35,7 @@ files:
35
35
  - README.md
36
36
  - Rakefile
37
37
  - amq-protocol.gemspec
38
+ - benchmarks/int_allocator.rb
38
39
  - benchmarks/pure/body_framing_with_256k_payload.rb
39
40
  - benchmarks/pure/body_framing_with_2k_payload.rb
40
41
  - codegen/__init__.py
@@ -102,7 +103,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
102
103
  version: '0'
103
104
  requirements: []
104
105
  rubyforge_project: amq-protocol
105
- rubygems_version: 2.0.5
106
+ rubygems_version: 2.1.6
106
107
  signing_key:
107
108
  specification_version: 4
108
109
  summary: AMQP 0.9.1 encoder & decoder.