vuf 1.0.1 → 1.1.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.
data/lib/vuf.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require "socket"
1
2
  require "thread"
2
3
  require "log4r"
3
4
 
@@ -7,6 +8,7 @@ require "vuf/working_pool"
7
8
  require "vuf/pool"
8
9
  require "vuf/batch"
9
10
  require "vuf/profiler"
11
+ require "vuf/server"
10
12
 
11
13
  module Vuf
12
14
  # Your code goes here...
@@ -17,27 +17,33 @@ module Vuf
17
17
  @stats[:counter][label] += 1
18
18
  }
19
19
  end
20
- def start(label)
21
- @mutex.synchronize { @timers[[Thread.current,label]] = Time.new }
20
+ def start(label,limit=nil)
21
+ @mutex.synchronize { @timers[[Thread.current,label]] = [Time.new,limit] }
22
22
  end
23
23
 
24
24
  def stop(label)
25
+ Logger.error "Invalid label #{label}" unless label.instance_of?(String) || label.instance_of?(Symbol)
25
26
  new_time = Time.new
26
27
  @mutex.synchronize {
27
- time = @timers.delete([Thread.current,label])
28
+ time,limit = @timers.delete([Thread.current,label])
28
29
  if time
29
30
  @stats[:time][label] ||= []
30
- @stats[:time][label] << new_time - time
31
+ t = new_time - time
32
+ if limit && t > limit
33
+ Logger.warn "Time limit exceeds for #{label} : #{t} s"
34
+ end
35
+ @stats[:time][label] << t
31
36
  end
32
37
  }
33
38
  end
34
39
 
35
40
  def result
36
- counter_stat = [] ; time_stat = []
41
+ counter_stat = [] ; time_stat = [] ; current_time = Time.new
37
42
  error = nil
38
43
  @mutex.synchronize {
39
44
  begin
40
- @stats[:counter].each{|k,v| counter_stat << "#{k} => #{v.to_s.rjust(10,' ')}" }
45
+ @stats[:counter].each{|k,v| counter_stat << [k, "#{k} => #{v.to_s.rjust(10,' ')}"] }
46
+ counter_stat = counter_stat.sort{|a,b| a.first <=> b.first}.collect{|a| a.last}
41
47
  @stats[:time].each{ |k,v|
42
48
  # retrieve previous av_time and number of mesures (nbdata)
43
49
  av_time,nbdata = @stats[:avtime][k]
@@ -52,10 +58,17 @@ module Vuf
52
58
  end
53
59
  av_time = cumul_time / nbdata
54
60
  time_stat << "#{k.to_s.rjust(20,' ')} => #{av_time.round(8).to_s.rjust(12,' ')} s/op " +
55
- "[#{nbdata.to_s.rjust(12,' ')} op| #{(nbdata*av_time).round(2).to_s.rjust(8,' ')} s]"
61
+ "[#{nbdata.to_s.rjust(12,' ')} op| #{(nbdata*av_time).round(2).to_s.rjust(8,' ')} s]"
56
62
  @stats[:avtime][k] = [av_time,nbdata]
57
63
  @stats[:time][k] = nil
58
- }
64
+ }
65
+ @timers.each{|k,v|
66
+ t = current_time - v.first
67
+ if v.last && ( t > v.last)
68
+ time_stat << "Timeout on #{k.last} : #{t} s"
69
+ end
70
+ }
71
+ # time_stat = time_stat.sort{|a,b| a.first <=> b.first}.collect{|a| a.last}
59
72
  rescue => e
60
73
  Logger.error {"Error in statistic #{e.message}\n#{e.backtrace.join("\n")}"}
61
74
  error = e
@@ -0,0 +1,85 @@
1
+ module Vuf
2
+ class Server
3
+
4
+ def initialize(port, session_klass)
5
+ @port = port
6
+ @sessions_ctx = {}
7
+ @server_thread = nil
8
+ @closing_q = Queue.new
9
+ @session_klass = session_klass
10
+ @wp = Vuf::WorkingPool.new(4)
11
+ @wp.run
12
+ end
13
+
14
+ def start
15
+ if @server_thread.nil?
16
+ @running = true
17
+ @server_thread = Thread.new do
18
+ Logger.debug "Server Starting"
19
+ begin
20
+ @server = TCPServer.new @port
21
+ @s_list = [@server]
22
+ while @running
23
+ close_ended_sessions
24
+ rsl, = IO.select(@s_list,[],[],1)
25
+ next if rsl.nil? # Timeout
26
+ accept(rsl) # Handle acceptance of new incoming session
27
+ rsl.each { |s| serve s }
28
+ end
29
+ rescue => e
30
+ Logger.error "Server Error [#{e}]
31
+ #{e.message}
32
+ #{e.backtrace.join("\n")}"
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ def shutdown
39
+ @running = false
40
+ @server_thread.join unless @server_thread.nil?
41
+ @server_thread = nil
42
+ end
43
+
44
+ private
45
+
46
+ def accept(selected)
47
+ serv = selected.delete(@server)
48
+ if serv
49
+ sock = serv.accept
50
+ @s_list << sock
51
+ @sessions_ctx[sock] = @session_klass.new(sock)
52
+ end
53
+ end
54
+
55
+ def serve(sock)
56
+ msg_recv = sock.recv_nonblock(1024)
57
+ if msg_recv.empty?
58
+ @closing_q << sock
59
+ else
60
+ session = @sessions_ctx[sock]
61
+ @wp.do(session,session,msg_recv) do |sess,msg|
62
+ ret = sess.handle(msg)
63
+ if ret.nil?
64
+ Logger.error "Handle return nil on msg #{msg} at step #{sess.step}"
65
+ end
66
+ end
67
+ end
68
+ end
69
+
70
+ def close_ended_sessions
71
+ until @closing_q.empty?
72
+ s = @closing_q.pop
73
+ session = @sessions_ctx.delete(s)
74
+ if session
75
+ @wp.do(session,session,s) do |sess,sock|
76
+ sess.finalize
77
+ sock.close
78
+ end
79
+ end
80
+ @s_list.delete(s)
81
+ end
82
+ end
83
+ end
84
+ end
85
+
@@ -1,3 +1,3 @@
1
1
  module Vuf
2
- VERSION = "1.0.1"
2
+ VERSION = "1.1.0"
3
3
  end
@@ -44,14 +44,19 @@ module Vuf
44
44
 
45
45
  def try_lock_channel(channel,task, args)
46
46
  new_channel_q = nil
47
+ error = nil
47
48
  @channels_mutex.synchronize {
48
49
  if @channels[channel].nil?
49
50
  new_channel_q = @channelsQ.shift
50
- raise "Missing queue in working pool" unless new_channel_q.instance_of?(Queue)
51
51
  @channels[channel]=new_channel_q
52
52
  end
53
- @channels[channel].push([task, args])
53
+ if @channels[channel].instance_of?(Queue)
54
+ @channels[channel].push([task, args])
55
+ else
56
+ error = "Missing queue in working pool"
57
+ end
54
58
  }
59
+ raise error unless error.nil?
55
60
  return new_channel_q
56
61
  end
57
62
 
@@ -1,4 +1,19 @@
1
1
  require_relative '../../test_helper'
2
+ class PoolKlass
3
+ include Vuf::Pool
4
+ attr_reader :i_index
5
+ def initialize
6
+ @@index ||= 0
7
+ @@index += 1
8
+ @i_index = @@index
9
+ end
10
+
11
+ def write(msg)
12
+ @f = File.open(File.join("test", "tmp", "file_#{@i_index}.txt"),"w+")
13
+ @f.write(msg)
14
+ @f.close
15
+ end
16
+ end
2
17
 
3
18
  describe Vuf::Pool do
4
19
  subject {
@@ -23,34 +38,25 @@ describe Vuf::Pool do
23
38
  end
24
39
  end
25
40
 
41
+
26
42
  describe Vuf::Pool do
27
- class PoolKlass
28
- include Vuf::Pool
29
- attr_reader :i_index
30
- def initialize
31
- @@index ||= 0
32
- @@index += 1
33
- @i_index = @@index
34
- @f = File.open(File.join("test", "tmp", "file_#{@@index}.txt"),"w+")
35
- end
36
-
37
- def write(msg)
38
- @f.write(msg)
39
- end
40
- end
41
-
42
43
 
43
44
  subject { 5 }
44
45
 
45
46
  it "must create 5 Files" do
46
47
  wp = Vuf::WorkingPool.new(subject)
47
48
  wp.run
48
- 1000.times do |i|
49
- wp.do do
50
- poolklass_instance = PoolKlass.instance
51
- poolklass_instance.write("Message #{i.to_s}\n")
52
- PoolKlass.release
53
- end
49
+ 100.times do |i|
50
+ wp.do(i,i) { |i|
51
+ begin
52
+ writer = PoolKlass.instance
53
+ writer.write("Message #{i.to_s}\n")
54
+ sleep 0.01
55
+ PoolKlass.release
56
+ rescue => e
57
+ Vuf::Logger.error "#{e}\n#{e.message}\n#{e.backtrace.join("\n")}"
58
+ end
59
+ }
54
60
  end
55
61
  wp.finalize
56
62
  Dir[File.join("test", "tmp","file_*.txt")].size.must_equal(subject)
@@ -4,6 +4,7 @@ describe Vuf::Profiler do
4
4
  subject { Vuf::Profiler.new }
5
5
 
6
6
  it "must parse options without errors" do
7
+ Vuf::Logger.outputters = Log4r::FileOutputter.new("profile_logger", {:filename => "test/tmp/log_profiler.log"})
7
8
  subject.run(0.1)
8
9
  10000.times do
9
10
  subject.start('test')
@@ -11,5 +12,6 @@ describe Vuf::Profiler do
11
12
  subject.stop('test')
12
13
  end
13
14
  subject.finalize
15
+ Vuf::Logger.outputters = Log4r::Outputter.stderr
14
16
  end
15
17
  end
@@ -0,0 +1,100 @@
1
+ require_relative '../../test_helper'
2
+
3
+ STEPS = ["IPDU_CN", "IPDU_AC", "MSG_804", "MSG_814", "MSG_306", "MSG_316",
4
+ "MSG_246", "MSG_256", "MSG_506", "MSG_516", nil]
5
+
6
+
7
+ class TestSession
8
+ attr_reader :step
9
+ def initialize(socket)
10
+ @sock = socket
11
+ @step = 0
12
+ end
13
+
14
+ def start
15
+ @sock.send STEPS.first, 0
16
+ @step += 1
17
+ end
18
+
19
+ def handle(msg)
20
+ curr_step = STEPS.index(msg)
21
+ if @step != curr_step
22
+ Vuf::Logger.error "Error received #{msg} on step #{@step}"
23
+ return nil
24
+ end
25
+ @step += 1
26
+ reply = STEPS[@step]
27
+ return nil if reply.nil?
28
+ no_reply = true
29
+ begin
30
+ @sock.send reply,0
31
+ no_reply = false
32
+ rescue => e
33
+ Vuf::Logger.error "Error on send #{reply} for #{@sock} => [#{e}]
34
+ #{e.message}
35
+ #{e.backtrace.join("\n")}"
36
+ ensure
37
+ if no_reply
38
+ Vuf::Logger.error "No reply send on session #{@sock} for msg #{msg} / reply #{reply} on step #{@step}"
39
+ end
40
+ end
41
+ @step += 1
42
+ return @step
43
+ end
44
+
45
+ def finalize
46
+ if @step != (STEPS.size - 1)
47
+ Vuf::Logger.error "Error finalize on step #{@step}"
48
+ end
49
+ end
50
+ end
51
+
52
+
53
+ class TestClient
54
+ def initialize(nb_req)
55
+ @nb_req = nb_req
56
+ end
57
+
58
+ def run
59
+ sockets = []
60
+ sessions = {}
61
+ done = 0 ; done_mutex = Mutex.new
62
+ nb_run=0
63
+ until done == @nb_req
64
+ while sockets.size < 20 && nb_run < @nb_req
65
+ nb_run += 1
66
+ s = TCPSocket.open('localhost',3527)
67
+ sockets << s
68
+ sessions[s] = TestSession.new(s)
69
+ sessions[s].start
70
+ end
71
+
72
+ rsl, = IO.select(sockets,[],[],1)
73
+
74
+ unless rsl.nil?
75
+ rsl.each do |s|
76
+ reply = s.recv(1024)
77
+ sess = sessions[s]
78
+ ret = sess.handle(reply)
79
+ if ret.nil?
80
+ s.close
81
+ done_mutex.synchronize { done += 1}
82
+ sockets.delete(s)
83
+ sessions.delete(s)
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
90
+
91
+ describe Vuf::Server do
92
+ subject { Vuf::Server.new(3527,TestSession) }
93
+
94
+ it "must parse options without errors" do
95
+ # Run the server with logging enabled (it's a separate thread).
96
+ subject.start
97
+ TestClient.new(100).run
98
+ subject.shutdown
99
+ end
100
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vuf
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-01-31 00:00:00.000000000 Z
12
+ date: 2014-02-25 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -60,11 +60,13 @@ files:
60
60
  - lib/vuf/logger.rb
61
61
  - lib/vuf/pool.rb
62
62
  - lib/vuf/profiler.rb
63
+ - lib/vuf/server.rb
63
64
  - lib/vuf/version.rb
64
65
  - lib/vuf/working_pool.rb
65
66
  - test/lib/vuf/batch_test.rb
66
67
  - test/lib/vuf/pool_test.rb
67
68
  - test/lib/vuf/profiler_test.rb
69
+ - test/lib/vuf/server_test.rb
68
70
  - test/lib/vuf/wp_test.rb
69
71
  - test/test_helper.rb
70
72
  - test/tmp/.gitignore
@@ -99,6 +101,7 @@ test_files:
99
101
  - test/lib/vuf/batch_test.rb
100
102
  - test/lib/vuf/pool_test.rb
101
103
  - test/lib/vuf/profiler_test.rb
104
+ - test/lib/vuf/server_test.rb
102
105
  - test/lib/vuf/wp_test.rb
103
106
  - test/test_helper.rb
104
107
  - test/tmp/.gitignore