amq-protocol 1.8.0 → 1.9.0
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 +4 -4
- data/.travis.yml +2 -4
- data/ChangeLog.md +20 -0
- data/README.md +1 -1
- data/benchmarks/int_allocator.rb +34 -0
- data/lib/amq/bit_set.rb +45 -8
- data/lib/amq/int_allocator.rb +11 -22
- data/lib/amq/protocol/version.rb +1 -1
- data/spec/amq/bit_set_spec.rb +106 -2
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4ac3c4778d62f3a7f84cd1132c77de339a2e97c3
|
4
|
+
data.tar.gz: 205cf9a34ea9addcfe2458e1dfcc9b6fe8a6c81c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ed02a18089fc8e1f633716981a1d995cf5ad6eb8663bdfb794effc32351dea6d97b56cbcea01a413f65d1ace0a56f1853bbe0bcce10072587c9439eb60d748d2
|
7
|
+
data.tar.gz: 0c2344d1e5919666c6b38934fe3f38817f117f117ed8606b6090c96e7e43c6e8afa556bbf4bf9e2e082e7bea75518ac5090f9d48d869525edb532fc67a95856e
|
data/.travis.yml
CHANGED
@@ -6,14 +6,12 @@ rvm:
|
|
6
6
|
- 1.9.3
|
7
7
|
- jruby-19mode
|
8
8
|
- 1.9.2
|
9
|
-
- rbx-
|
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@
|
14
|
+
- michael@rabbitmq.com
|
17
15
|
matrix:
|
18
16
|
allow_failures:
|
19
17
|
- rvm: ruby-head
|
data/ChangeLog.md
CHANGED
@@ -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
|
[](https://travis-ci.org/ruby-amqp/amq-protocol)
|
44
44
|
|
45
45
|
|
46
|
-
##
|
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
|
data/lib/amq/bit_set.rb
CHANGED
@@ -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) {
|
110
|
+
@words = Array.new(n) { 0 }
|
75
111
|
end # init_words
|
76
112
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
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
|
data/lib/amq/int_allocator.rb
CHANGED
@@ -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
|
-
|
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
|
data/lib/amq/protocol/version.rb
CHANGED
data/spec/amq/bit_set_spec.rb
CHANGED
@@ -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
|
-
|
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.
|
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-
|
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.
|
106
|
+
rubygems_version: 2.1.6
|
106
107
|
signing_key:
|
107
108
|
specification_version: 4
|
108
109
|
summary: AMQP 0.9.1 encoder & decoder.
|