funl 0.5 → 0.6
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/README.md +5 -1
- data/bench/funl-bench.rb +132 -0
- data/bench/msg-rate.rb +56 -0
- data/lib/funl/message-sequencer-nio.rb +37 -0
- data/lib/funl/message-sequencer-select.rb +38 -0
- data/lib/funl/message-sequencer.rb +57 -54
- data/lib/funl/version.rb +1 -1
- data/test/test-message-sequencer.rb +20 -4
- metadata +23 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0b5ff91baeb01956c2e26427666b5ce60086a777
|
4
|
+
data.tar.gz: 49f96709858f97aa437782f3059dcda83d69cc39
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 022c1cfec28b024802f721039fbfe7aa5a4adff0f11b2f3bac58507dbdf6142a0507f340a85c9ce04d106424d617bd960911cb47fedb38431ed5735897e30217
|
7
|
+
data.tar.gz: fc5c636c27a20f99600f1c8fa208794cade737d11a225d6f9d054ead7fa033c42c0c24e7130a69ce69e9f3fee481349f7a1c5c7560eb59cea4d08e97f21b1571
|
data/README.md
CHANGED
data/bench/funl-bench.rb
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
require 'funl/message-sequencer-select'
|
2
|
+
require 'funl/message-sequencer-nio'
|
3
|
+
require 'socket'
|
4
|
+
require 'tmpdir'
|
5
|
+
|
6
|
+
include Funl
|
7
|
+
|
8
|
+
class BenchmarkTask
|
9
|
+
attr_reader :name, :params
|
10
|
+
|
11
|
+
def initialize name, **params
|
12
|
+
@name = name
|
13
|
+
@params = params
|
14
|
+
end
|
15
|
+
|
16
|
+
def inspect
|
17
|
+
ps = params.map{|k,v| "#{k}: #{v}" }
|
18
|
+
pstr = ps.empty? ? "" : " " + ps.join(', ')
|
19
|
+
"<#{name}#{pstr}>"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class WarmupTask < BenchmarkTask
|
24
|
+
def run make_stream
|
25
|
+
make_stream["1"]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# All clients run in the same process; mseq server is in a child process.
|
30
|
+
class BenchmarkEnv
|
31
|
+
attr_reader :name, :dir, :path, :log, :stream_type, :tasks, :mseq_class
|
32
|
+
|
33
|
+
def initialize name, stream_type: ObjectStream::MSGPACK_TYPE,
|
34
|
+
mseq_class: MessageSequencer
|
35
|
+
@name = name
|
36
|
+
@log = Logger.new($stderr)
|
37
|
+
log.level = Logger::WARN
|
38
|
+
@stream_type = stream_type
|
39
|
+
@tasks = []
|
40
|
+
@mseq_class = mseq_class
|
41
|
+
end
|
42
|
+
|
43
|
+
def add_task task
|
44
|
+
@tasks << task
|
45
|
+
end
|
46
|
+
alias << add_task
|
47
|
+
|
48
|
+
def run
|
49
|
+
@dir = Dir.mktmpdir "funl-benchmark-#{name}-"
|
50
|
+
@path = File.join(dir, "sock")
|
51
|
+
svr = UNIXServer.new(path)
|
52
|
+
s0, s1 = UNIXSocket.pair
|
53
|
+
@pid = fork do
|
54
|
+
run_server svr, s1
|
55
|
+
end
|
56
|
+
|
57
|
+
log.progname = "client"
|
58
|
+
|
59
|
+
@mseq_ctrl = ObjectStreamWrapper.new(s0, type: stream_type)
|
60
|
+
|
61
|
+
puts mseq_class
|
62
|
+
printf "%6s %6s | %s\n", "client", "server", "task"
|
63
|
+
puts "-"*60
|
64
|
+
tasks.each do |task|
|
65
|
+
run_task task
|
66
|
+
end
|
67
|
+
ensure
|
68
|
+
close
|
69
|
+
end
|
70
|
+
|
71
|
+
def run_server svr, s
|
72
|
+
log.progname = "#{name}-mseq"
|
73
|
+
mseq = mseq_class.new svr, log: log, stream_type: stream_type
|
74
|
+
mseq.start
|
75
|
+
|
76
|
+
run_control_loop(s)
|
77
|
+
rescue => ex
|
78
|
+
log.error ex
|
79
|
+
end
|
80
|
+
|
81
|
+
def run_control_loop s
|
82
|
+
t0 = Process.times
|
83
|
+
stream = ObjectStreamWrapper.new(s, type: stream_type)
|
84
|
+
loop do
|
85
|
+
stream.read do |msg|
|
86
|
+
case msg
|
87
|
+
when "dt"
|
88
|
+
t1 = Process.times
|
89
|
+
dt = t1.utime + t1.stime - (t0.utime + t0.stime)
|
90
|
+
t0 = t1
|
91
|
+
stream << dt
|
92
|
+
## when GC start|enable|disable
|
93
|
+
else
|
94
|
+
raise "unknown control message: #{msg.inspect}"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def run_task task
|
101
|
+
t0 = Process.times
|
102
|
+
@mseq_ctrl << "dt"
|
103
|
+
task.run method(:make_stream)
|
104
|
+
t1 = Process.times
|
105
|
+
@mseq_ctrl << "dt"
|
106
|
+
|
107
|
+
@mseq_ctrl.read
|
108
|
+
dt = @mseq_ctrl.read
|
109
|
+
|
110
|
+
time = t1.utime + t1.stime - (t0.utime + t0.stime)
|
111
|
+
printf "%6.3f %6.3f | %p\n", time, dt, task
|
112
|
+
rescue => ex
|
113
|
+
log.error "#{task.inspect}: #{ex}"
|
114
|
+
end
|
115
|
+
|
116
|
+
def make_stream client_id = nil ## subscriptions?
|
117
|
+
conn = UNIXSocket.new(path)
|
118
|
+
stream = ObjectStreamWrapper.new(conn, type: stream_type)
|
119
|
+
stream.write_to_outbox({"client_id" => client_id})
|
120
|
+
stream.write(Message.control(SUBSCRIBE_ALL))
|
121
|
+
global_tick = stream.read["tick"]
|
122
|
+
stream.expect Message
|
123
|
+
ack = stream.read
|
124
|
+
stream
|
125
|
+
end
|
126
|
+
|
127
|
+
def close
|
128
|
+
Process.kill "TERM", @pid if @pid
|
129
|
+
Process.waitpid @pid
|
130
|
+
FileUtils.remove_entry dir if dir
|
131
|
+
end
|
132
|
+
end
|
data/bench/msg-rate.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
require_relative 'funl-bench'
|
2
|
+
|
3
|
+
# Measure the message rate through the sequencer.
|
4
|
+
class MessageRateBenchmarkTask < BenchmarkTask
|
5
|
+
def run make_stream
|
6
|
+
n_msg = params[:n_msg] || 10
|
7
|
+
n_cli = params[:n_cli] || 2
|
8
|
+
cycle_sender = params[:cycle_sender] || false
|
9
|
+
|
10
|
+
streams = n_cli.times.map {|i| make_stream[i]}
|
11
|
+
threads = n_cli.times.map do |i|
|
12
|
+
Thread.new do
|
13
|
+
n_msg.times do
|
14
|
+
streams[i].read
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
n_msg.times do |i|
|
20
|
+
stream = cycle_sender ? streams[i % n_cli] : streams[0]
|
21
|
+
stream <<
|
22
|
+
Message[client: "1", local: i, global: nil, delta: nil,
|
23
|
+
tags: nil, blob: nil]
|
24
|
+
end
|
25
|
+
|
26
|
+
threads.each {|th| th.join}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
if __FILE__ == $0
|
31
|
+
b_sel = BenchmarkEnv.new("msg-rate", mseq_class: MessageSequencerSelect)
|
32
|
+
|
33
|
+
b_sel << WarmupTask.new("warmup")
|
34
|
+
b_sel << MessageRateBenchmarkTask.new("msg rate", n_msg: 100, n_cli: 2)
|
35
|
+
b_sel << MessageRateBenchmarkTask.new("msg rate", n_msg: 1000, n_cli: 2)
|
36
|
+
b_sel << MessageRateBenchmarkTask.new("msg rate", n_msg: 1000, n_cli: 10)
|
37
|
+
# b_sel << MessageRateBenchmarkTask.new("msg rate", n_msg: 1000, n_cli: 10,
|
38
|
+
# cycle_sender: false)
|
39
|
+
# b_sel << MessageRateBenchmarkTask.new("msg rate", n_msg: 1000, n_cli: 100)
|
40
|
+
|
41
|
+
b_sel.run
|
42
|
+
|
43
|
+
puts
|
44
|
+
|
45
|
+
b_nio = BenchmarkEnv.new("msg-rate", mseq_class: MessageSequencerNio)
|
46
|
+
|
47
|
+
b_nio << WarmupTask.new("warmup")
|
48
|
+
b_nio << MessageRateBenchmarkTask.new("msg rate", n_msg: 100, n_cli: 2)
|
49
|
+
b_nio << MessageRateBenchmarkTask.new("msg rate", n_msg: 1000, n_cli: 2)
|
50
|
+
b_nio << MessageRateBenchmarkTask.new("msg rate", n_msg: 1000, n_cli: 10)
|
51
|
+
# b_nio << MessageRateBenchmarkTask.new("msg rate", n_msg: 1000, n_cli: 10,
|
52
|
+
# cycle_sender: false)
|
53
|
+
# b_nio << MessageRateBenchmarkTask.new("msg rate", n_msg: 1000, n_cli: 100)
|
54
|
+
|
55
|
+
b_nio.run
|
56
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'nio'
|
2
|
+
require 'funl/message-sequencer'
|
3
|
+
|
4
|
+
module Funl
|
5
|
+
class MessageSequencerNio < MessageSequencer
|
6
|
+
private
|
7
|
+
|
8
|
+
attr_reader :selector
|
9
|
+
|
10
|
+
def init_selector
|
11
|
+
@selector = NIO::Selector.new
|
12
|
+
if server
|
13
|
+
monitor = selector.register server, :r
|
14
|
+
monitor.value = proc {accept_conn}
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def register_stream stream
|
19
|
+
monitor = selector.register stream, :r
|
20
|
+
monitor.value = proc {read_conn stream}
|
21
|
+
end
|
22
|
+
|
23
|
+
def deregister_stream stream
|
24
|
+
selector.deregister stream
|
25
|
+
end
|
26
|
+
|
27
|
+
def registered_stream? stream
|
28
|
+
selector.registered? stream
|
29
|
+
end
|
30
|
+
|
31
|
+
def select_streams
|
32
|
+
selector.select do |monitor|
|
33
|
+
monitor.value.call(monitor)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'funl/message-sequencer'
|
2
|
+
|
3
|
+
module Funl
|
4
|
+
class MessageSequencerSelect < MessageSequencer
|
5
|
+
private
|
6
|
+
|
7
|
+
attr_reader :streams
|
8
|
+
|
9
|
+
def init_selector
|
10
|
+
@streams = []
|
11
|
+
end
|
12
|
+
|
13
|
+
def register_stream stream
|
14
|
+
streams << stream
|
15
|
+
end
|
16
|
+
|
17
|
+
def deregister_stream stream
|
18
|
+
streams.delete stream
|
19
|
+
end
|
20
|
+
|
21
|
+
def registered_stream? stream
|
22
|
+
streams.include? stream
|
23
|
+
end
|
24
|
+
|
25
|
+
def select_streams
|
26
|
+
readables, _ = select [server, *streams]
|
27
|
+
|
28
|
+
readables.each do |readable|
|
29
|
+
case readable
|
30
|
+
when server
|
31
|
+
accept_conn
|
32
|
+
else
|
33
|
+
read_conn readable
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -11,7 +11,6 @@ module Funl
|
|
11
11
|
|
12
12
|
attr_reader :server
|
13
13
|
attr_reader :server_thread
|
14
|
-
attr_reader :streams
|
15
14
|
attr_reader :tick
|
16
15
|
attr_reader :log
|
17
16
|
attr_reader :stream_type
|
@@ -19,6 +18,15 @@ module Funl
|
|
19
18
|
attr_reader :blob_type
|
20
19
|
attr_reader :greeting
|
21
20
|
attr_reader :subscribers
|
21
|
+
|
22
|
+
def self.new *a
|
23
|
+
if self == MessageSequencer
|
24
|
+
require 'funl/message-sequencer-select'
|
25
|
+
MessageSequencerSelect.new *a
|
26
|
+
else
|
27
|
+
super
|
28
|
+
end
|
29
|
+
end
|
22
30
|
|
23
31
|
def initialize server, *conns, log: Logger.new($stderr),
|
24
32
|
stream_type: ObjectStream::MSGPACK_TYPE,
|
@@ -34,7 +42,8 @@ module Funl
|
|
34
42
|
@greeting = default_greeting
|
35
43
|
@tick = tick
|
36
44
|
|
37
|
-
|
45
|
+
init_selector
|
46
|
+
|
38
47
|
conns.each do |conn|
|
39
48
|
try_conn conn
|
40
49
|
end
|
@@ -50,16 +59,6 @@ module Funl
|
|
50
59
|
}.freeze # can't change after initial conns read it
|
51
60
|
end
|
52
61
|
|
53
|
-
def try_conn conn
|
54
|
-
stream = message_server_stream_for(conn)
|
55
|
-
current_greeting = greeting.merge({"tick" => tick})
|
56
|
-
if write_succeeds?(current_greeting, stream)
|
57
|
-
log.debug {"connected #{stream.inspect}"}
|
58
|
-
streams << stream
|
59
|
-
end
|
60
|
-
end
|
61
|
-
private :try_conn
|
62
|
-
|
63
62
|
def start
|
64
63
|
@server_thread = Thread.new do
|
65
64
|
run
|
@@ -73,52 +72,58 @@ module Funl
|
|
73
72
|
def wait
|
74
73
|
server_thread.join
|
75
74
|
end
|
76
|
-
|
75
|
+
|
77
76
|
def run
|
78
77
|
loop do
|
79
|
-
|
80
|
-
|
81
|
-
readables.each do |readable|
|
82
|
-
case readable
|
83
|
-
when server
|
84
|
-
begin
|
85
|
-
conn, addr = readable.accept_nonblock
|
86
|
-
log.debug {"accepted #{conn.inspect} from #{addr.inspect}"}
|
87
|
-
try_conn conn
|
88
|
-
rescue IO::WaitReadable
|
89
|
-
next
|
90
|
-
end
|
91
|
-
|
92
|
-
else
|
93
|
-
log.debug {"readable = #{readable}"}
|
94
|
-
begin
|
95
|
-
msgs = []
|
96
|
-
readable.read do |msg|
|
97
|
-
msgs << msg
|
98
|
-
end
|
99
|
-
rescue IOError, SystemCallError => ex
|
100
|
-
log.debug {"closing #{readable}: #{ex}"}
|
101
|
-
reject_stream readable
|
102
|
-
else
|
103
|
-
log.debug {
|
104
|
-
"read #{msgs.size} messages from #{readable.peer_name}"}
|
105
|
-
end
|
106
|
-
|
107
|
-
msgs.each do |msg|
|
108
|
-
if msg.control?
|
109
|
-
handle_control readable, *msg.control_op
|
110
|
-
else
|
111
|
-
handle_message msg, readable
|
112
|
-
end
|
113
|
-
end
|
114
|
-
end
|
115
|
-
end
|
78
|
+
select_streams
|
116
79
|
end
|
117
80
|
rescue => ex
|
118
81
|
log.error ex
|
119
82
|
raise
|
120
83
|
end
|
121
84
|
|
85
|
+
private
|
86
|
+
|
87
|
+
def accept_conn
|
88
|
+
conn, addr = server.accept_nonblock
|
89
|
+
log.debug {"accepted #{conn.inspect} from #{addr.inspect}"}
|
90
|
+
try_conn conn
|
91
|
+
rescue IO::WaitReadable
|
92
|
+
end
|
93
|
+
|
94
|
+
def try_conn conn
|
95
|
+
stream = message_server_stream_for(conn)
|
96
|
+
current_greeting = greeting.merge({"tick" => tick})
|
97
|
+
if write_succeeds?(current_greeting, stream)
|
98
|
+
log.debug {"connected #{stream.inspect}"}
|
99
|
+
register_stream stream
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def read_conn readable
|
104
|
+
log.debug {"readable = #{readable}"}
|
105
|
+
begin
|
106
|
+
msgs = []
|
107
|
+
readable.read do |msg|
|
108
|
+
msgs << msg
|
109
|
+
end
|
110
|
+
rescue IOError, SystemCallError => ex
|
111
|
+
log.debug {"closing #{readable}: #{ex}"}
|
112
|
+
reject_stream readable
|
113
|
+
else
|
114
|
+
log.debug {
|
115
|
+
"read #{msgs.size} messages from #{readable.peer_name}"}
|
116
|
+
end
|
117
|
+
|
118
|
+
msgs.each do |msg|
|
119
|
+
if msg.control?
|
120
|
+
handle_control readable, *msg.control_op
|
121
|
+
else
|
122
|
+
handle_message msg, readable
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
122
127
|
def handle_control stream, op_type, tags = nil
|
123
128
|
log.debug {"#{stream.peer_name} #{op_type} #{tags}"}
|
124
129
|
|
@@ -181,7 +186,6 @@ module Funl
|
|
181
186
|
write_succeeds? msg, stream
|
182
187
|
end
|
183
188
|
end
|
184
|
-
private :handle_message
|
185
189
|
|
186
190
|
def write_succeeds? data, stream
|
187
191
|
stream << data
|
@@ -191,12 +195,11 @@ module Funl
|
|
191
195
|
reject_stream stream
|
192
196
|
false
|
193
197
|
end
|
194
|
-
private :write_succeeds?
|
195
198
|
|
196
199
|
def reject_stream stream
|
197
200
|
stream.close unless stream.closed?
|
198
|
-
if
|
199
|
-
|
201
|
+
if registered_stream? stream
|
202
|
+
deregister_stream stream
|
200
203
|
@subscribers_to_all.delete stream
|
201
204
|
tags = @tags.delete stream
|
202
205
|
if tags
|
data/lib/funl/version.rb
CHANGED
@@ -1,4 +1,13 @@
|
|
1
1
|
require 'funl/message-sequencer'
|
2
|
+
|
3
|
+
have_nio = begin
|
4
|
+
require 'funl/message-sequencer-nio'
|
5
|
+
rescue LoadError
|
6
|
+
false
|
7
|
+
else
|
8
|
+
true
|
9
|
+
end
|
10
|
+
|
2
11
|
require 'socket'
|
3
12
|
require 'tmpdir'
|
4
13
|
|
@@ -8,6 +17,8 @@ require 'minitest/autorun'
|
|
8
17
|
|
9
18
|
class TestMessageSequencer < Minitest::Test
|
10
19
|
attr_reader :log
|
20
|
+
|
21
|
+
def mseq_class; MessageSequencer; end
|
11
22
|
|
12
23
|
def setup
|
13
24
|
@dir = Dir.mktmpdir "funl-test-mseq-"
|
@@ -24,7 +35,7 @@ class TestMessageSequencer < Minitest::Test
|
|
24
35
|
def test_initial_conns
|
25
36
|
as = []; bs = []
|
26
37
|
@n_clients.times {a, b = UNIXSocket.pair; as << a; bs << b}
|
27
|
-
mseq =
|
38
|
+
mseq = mseq_class.new nil, *as, log: log
|
28
39
|
bs.each_with_index do |b, i|
|
29
40
|
stream = ObjectStreamWrapper.new(b, type: mseq.stream_type)
|
30
41
|
stream.write_to_outbox({"client_id" => "test_initial_conns #{i}"})
|
@@ -38,7 +49,7 @@ class TestMessageSequencer < Minitest::Test
|
|
38
49
|
svr = UNIXServer.new(@path)
|
39
50
|
pid = fork do
|
40
51
|
log.progname = "mseq"
|
41
|
-
mseq =
|
52
|
+
mseq = mseq_class.new svr, log: log, stream_type: stream_type
|
42
53
|
mseq.start
|
43
54
|
sleep
|
44
55
|
end
|
@@ -103,8 +114,7 @@ class TestMessageSequencer < Minitest::Test
|
|
103
114
|
|
104
115
|
path = "#{@path}-#{i}"
|
105
116
|
svr = UNIXServer.new(path)
|
106
|
-
mseq =
|
107
|
-
tick: saved_tick
|
117
|
+
mseq = mseq_class.new svr, log: log, tick: saved_tick
|
108
118
|
mseq.start
|
109
119
|
|
110
120
|
conn = UNIXSocket.new(path)
|
@@ -132,3 +142,9 @@ class TestMessageSequencer < Minitest::Test
|
|
132
142
|
mseq.stop rescue nil
|
133
143
|
end
|
134
144
|
end
|
145
|
+
|
146
|
+
if have_nio
|
147
|
+
class TestMessageSequencerNio < TestMessageSequencer
|
148
|
+
def mseq_class; MessageSequencerNio; end
|
149
|
+
end
|
150
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: funl
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.6'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joel VanderWerf
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-11-
|
11
|
+
date: 2013-11-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: object-stream
|
@@ -35,23 +35,27 @@ files:
|
|
35
35
|
- README.md
|
36
36
|
- COPYING
|
37
37
|
- Rakefile
|
38
|
-
- lib/funl/client-sequencer.rb
|
39
|
-
- lib/funl/message-sequencer.rb
|
40
|
-
- lib/funl/history-worker.rb
|
41
38
|
- lib/funl/stream.rb
|
42
|
-
- lib/funl/
|
43
|
-
- lib/funl/history-client.rb
|
39
|
+
- lib/funl/blobber.rb
|
44
40
|
- lib/funl/subscription-tracker.rb
|
41
|
+
- lib/funl/history-client.rb
|
42
|
+
- lib/funl/history-worker.rb
|
43
|
+
- lib/funl/client.rb
|
44
|
+
- lib/funl/message-sequencer.rb
|
45
|
+
- lib/funl/message-sequencer-nio.rb
|
46
|
+
- lib/funl/client-sequencer.rb
|
45
47
|
- lib/funl/message.rb
|
46
|
-
- lib/funl/blobber.rb
|
47
48
|
- lib/funl/version.rb
|
48
|
-
-
|
49
|
-
-
|
50
|
-
-
|
49
|
+
- lib/funl/message-sequencer-select.rb
|
50
|
+
- bench/msg-rate.rb
|
51
|
+
- bench/funl-bench.rb
|
52
|
+
- test/test-message-sequencer.rb
|
51
53
|
- test/test-client-sequencer.rb
|
52
|
-
- test/test-subscribe.rb
|
53
54
|
- test/test-reflect.rb
|
54
|
-
- test/test-message
|
55
|
+
- test/test-message.rb
|
56
|
+
- test/test-stream.rb
|
57
|
+
- test/test-subscribe.rb
|
58
|
+
- test/test-client.rb
|
55
59
|
homepage: https://github.com/vjoel/funl
|
56
60
|
licenses:
|
57
61
|
- BSD
|
@@ -79,16 +83,16 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
79
83
|
version: '0'
|
80
84
|
requirements: []
|
81
85
|
rubyforge_project:
|
82
|
-
rubygems_version: 2.1.
|
86
|
+
rubygems_version: 2.1.11
|
83
87
|
signing_key:
|
84
88
|
specification_version: 4
|
85
89
|
summary: Sequences messages
|
86
90
|
test_files:
|
87
|
-
- test/test-
|
88
|
-
- test/test-message.rb
|
89
|
-
- test/test-client.rb
|
91
|
+
- test/test-message-sequencer.rb
|
90
92
|
- test/test-client-sequencer.rb
|
91
|
-
- test/test-subscribe.rb
|
92
93
|
- test/test-reflect.rb
|
93
|
-
- test/test-message
|
94
|
+
- test/test-message.rb
|
95
|
+
- test/test-stream.rb
|
96
|
+
- test/test-subscribe.rb
|
97
|
+
- test/test-client.rb
|
94
98
|
has_rdoc:
|