vuf 1.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
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