norikra 0.0.11-java → 0.0.12-java
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +8 -0
- data/lib/norikra/cli.rb +60 -28
- data/lib/norikra/engine.rb +9 -4
- data/lib/norikra/error.rb +1 -0
- data/lib/norikra/output_pool.rb +22 -6
- data/lib/norikra/query.rb +4 -3
- data/lib/norikra/rpc/handler.rb +5 -5
- data/lib/norikra/rpc/http.rb +10 -4
- data/lib/norikra/rubyudf.rb +47 -47
- data/lib/norikra/server.rb +100 -11
- data/lib/norikra/stats.rb +33 -0
- data/lib/norikra/target.rb +7 -0
- data/lib/norikra/typedef.rb +19 -7
- data/lib/norikra/typedef_manager.rb +6 -0
- data/lib/norikra/version.rb +1 -1
- data/norikra.gemspec +1 -1
- data/spec/output_pool_spec.rb +42 -15
- data/spec/query_spec.rb +28 -2
- data/spec/stats_spec.rb +53 -0
- data/spec/target_spec.rb +24 -0
- data/spec/typedef_manager_spec.rb +26 -0
- data/spec/typedef_spec.rb +22 -0
- metadata +17 -4
data/.travis.yml
ADDED
data/lib/norikra/cli.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'norikra/server'
|
2
|
+
require 'norikra/error'
|
2
3
|
require 'thor'
|
3
4
|
|
4
5
|
module Norikra
|
@@ -6,9 +7,13 @@ module Norikra
|
|
6
7
|
desc "start", "start Norikra server process"
|
7
8
|
|
8
9
|
### Server options
|
9
|
-
option :host, :type => :string, :default =>
|
10
|
-
option :port, :type => :numeric, :default =>
|
11
|
-
|
10
|
+
option :host, :type => :string, :default => nil, :aliases => "-H", :desc => 'host address that server listen [0.0.0.0]'
|
11
|
+
option :port, :type => :numeric, :default => nil, :aliases => "-P", :desc => 'port that server uses [26571]'
|
12
|
+
|
13
|
+
option :stats, :type => :string, :default => nil, :aliases => "-s", \
|
14
|
+
:desc => 'status file path to load/dump targets, queries and server configurations [none]'
|
15
|
+
option :'suppress-dump-stat', :type => :boolean, :default => false, \
|
16
|
+
:desc => 'specify not to update stat file with updated targets/queries/configurations on runtime [false]'
|
12
17
|
|
13
18
|
### Execution options
|
14
19
|
option :daemonize, :type => :boolean, :default => false, :aliases => "-d", \
|
@@ -17,20 +22,32 @@ module Norikra
|
|
17
22
|
:desc => "pidfile path when daemonized [/var/run/norikra.pid]"
|
18
23
|
|
19
24
|
### Performance options
|
20
|
-
|
21
|
-
option :
|
22
|
-
|
23
|
-
option :
|
24
|
-
|
25
|
-
option :
|
26
|
-
|
27
|
-
option :
|
25
|
+
# performance predefined configuration sets
|
26
|
+
option :micro, :type => :boolean, :default => false, \
|
27
|
+
:desc => 'development or testing (inbound:0, outbound:0, route:0, timer:0, rpc:2)'
|
28
|
+
option :small, :type => :boolean, :default => false, \
|
29
|
+
:desc => 'virtual or small scale servers (inbound:1, outbount:1, route:1, timer:1, rpc:2)'
|
30
|
+
option :middle, :type => :boolean, :default => false, \
|
31
|
+
:desc => 'rackmount servers (inbound:4, outbound:2, route:2, timer:2, rpc:4)'
|
32
|
+
option :large, :type => :boolean, :default => false, \
|
33
|
+
:desc => 'high performance servers (inbound: 6, outbound: 6, route:4, timer:4, rpc: 8)'
|
34
|
+
# Esper
|
35
|
+
option :'inbound-threads', :type => :numeric, :default => nil, :desc => 'number of threads for inbound data'
|
36
|
+
option :'outbound-threads', :type => :numeric, :default => nil, :desc => 'number of threads for outbound data'
|
37
|
+
option :'route-threads', :type => :numeric, :default => nil, :desc => 'number of threads for events routing for query execution'
|
38
|
+
option :'timer-threads', :type => :numeric, :default => nil, :desc => 'number of threads for internal timers for query execution'
|
39
|
+
option :'inbound-thread-capacity', :type => :numeric, :default => nil
|
40
|
+
option :'outbound-thread-capacity', :type => :numeric, :default => nil
|
41
|
+
option :'route-thread-capacity', :type => :numeric, :default => nil
|
42
|
+
option :'timer-thread-capacity', :type => :numeric, :default => nil
|
43
|
+
# Jetty
|
44
|
+
option :'rpc-threads', :type => :numeric, :default => nil, :desc => 'number of threads for rpc handlers'
|
28
45
|
|
29
46
|
### Logging options
|
30
47
|
option :logdir, :type => :string, :default => nil, :aliases => "-l", \
|
31
48
|
:desc => "directory path of logfiles when daemonized [nil (console)]"
|
32
|
-
option :'log-filesize', :type => :string, :default => '10MB'
|
33
|
-
option :'log-backups' , :type => :numeric, :default => 10
|
49
|
+
option :'log-filesize', :type => :string, :default => nil, :desc => 'log rotation size [10MB]'
|
50
|
+
option :'log-backups' , :type => :numeric, :default => nil, :desc => 'log rotation backups [10]'
|
34
51
|
|
35
52
|
### Loglevel options
|
36
53
|
option :'more-quiet', :type => :boolean, :default => false, :desc => 'set loglevel as ERROR'
|
@@ -38,7 +55,6 @@ module Norikra
|
|
38
55
|
option :verbose, :type => :boolean, :default => false, :aliases => "-v", :desc => 'set loglevel as DEBUG'
|
39
56
|
option :'more-verbose', :type => :boolean, :default => false, :desc => 'set loglevel as TRACE'
|
40
57
|
|
41
|
-
#TODO: configuration file to init
|
42
58
|
def start
|
43
59
|
conf = {}
|
44
60
|
|
@@ -46,23 +62,39 @@ module Norikra
|
|
46
62
|
raise NotImplementedError if options[:daemonize]
|
47
63
|
#TODO: pidcheck if daemonize
|
48
64
|
|
65
|
+
### stat file
|
66
|
+
conf[:stats] = {
|
67
|
+
path: options[:stats], suppress: options[:'suppress-dump-stat'],
|
68
|
+
}
|
69
|
+
|
70
|
+
### threads
|
71
|
+
predefined_selecteds = [:micro, :small, :middle, :larage].select{|sym| options[sym]}
|
72
|
+
if predefined_selecteds.size > 1
|
73
|
+
raise Norikra::ConfigurationError, "one of micro/small/middle/large should be specified"
|
74
|
+
end
|
49
75
|
conf[:thread] = {
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
76
|
+
predefined: predefined_selecteds.first,
|
77
|
+
micro: options[:micro], small: options[:small], middle: options[:middle], large: options[:large],
|
78
|
+
engine: {inbound:{}, outbound:{}, route_exec:{}, timer_exec:{}},
|
79
|
+
rpc: {},
|
54
80
|
}
|
81
|
+
[:inbound, :outbound, :route_exec, :timer_exec].each do |sym|
|
82
|
+
conf[:thread][:engine][sym][:threads] = options[:"#{sym}-threads"] if options[:"#{sym}-threads"]
|
83
|
+
conf[:thread][:engine][sym][:capacity] = options[:"#{sym}-thread-capacity"] if options[:"#{sym}-thread-capacity"]
|
84
|
+
end
|
85
|
+
conf[:thread][:rpc][:threads] = options[:'rpc-threads'] if options[:'rpc-threads']
|
55
86
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
conf[:
|
65
|
-
|
87
|
+
### logs
|
88
|
+
loglevel = case
|
89
|
+
when options[:'more-verbose'] then 'TRACE'
|
90
|
+
when options[:verbose] then 'DEBUG'
|
91
|
+
when options[:quiet] then 'WARN'
|
92
|
+
when options[:'more-quiet'] then 'ERROR'
|
93
|
+
else nil # for default (assumed as 'INFO')
|
94
|
+
end
|
95
|
+
conf[:log] = {
|
96
|
+
level: loglevel, dir: options[:logdir], filesize: options[:'log-filesize'], backups: options[:'log-backups'],
|
97
|
+
}
|
66
98
|
|
67
99
|
server = Norikra::Server.new( options[:host], options[:port], conf )
|
68
100
|
server.run
|
data/lib/norikra/engine.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'java'
|
2
2
|
|
3
3
|
require 'norikra/error'
|
4
|
+
require 'norikra/target'
|
4
5
|
|
5
6
|
require 'norikra/logger'
|
6
7
|
include Norikra::Log
|
@@ -78,8 +79,11 @@ module Norikra
|
|
78
79
|
end
|
79
80
|
|
80
81
|
def open(target, fields=nil)
|
82
|
+
# fields nil || [] => lazy
|
83
|
+
# fields {'fieldname' => 'type'} : type 'string', 'boolean', 'int', 'long', 'float', 'double'
|
81
84
|
info "opening target", :target => target, :fields => fields
|
82
85
|
return false if @targets.include?(target)
|
86
|
+
raise Norikra::ArgumentError, "invalid target name" unless Norikra::Target.valid?(target)
|
83
87
|
open_target(target, fields)
|
84
88
|
end
|
85
89
|
|
@@ -161,8 +165,9 @@ module Norikra
|
|
161
165
|
class Listener
|
162
166
|
include com.espertech.esper.client.UpdateListener
|
163
167
|
|
164
|
-
def initialize(query_name, output_pool)
|
168
|
+
def initialize(query_name, query_group, output_pool)
|
165
169
|
@query_name = query_name
|
170
|
+
@query_group = query_group
|
166
171
|
@output_pool = output_pool
|
167
172
|
end
|
168
173
|
|
@@ -182,8 +187,8 @@ module Norikra
|
|
182
187
|
def update(new_events, old_events)
|
183
188
|
t = Time.now.to_i
|
184
189
|
events = new_events.map{|e| [t, type_convert(e)]}
|
185
|
-
trace "updated event", :query => @query_name, :event => events
|
186
|
-
@output_pool.push(@query_name, events)
|
190
|
+
trace "updated event", :query => @query_name, :group => @query_group, :event => events
|
191
|
+
@output_pool.push(@query_name, @query_group, events)
|
187
192
|
end
|
188
193
|
end
|
189
194
|
##### Unmatched events are simply ignored
|
@@ -357,7 +362,7 @@ module Norikra
|
|
357
362
|
Norikra::Query.rewrite_event_type_name(statement_model, event_type_name_map)
|
358
363
|
|
359
364
|
epl = administrator.create(statement_model)
|
360
|
-
epl.java_send :addListener, [com.espertech.esper.client.UpdateListener.java_class], Listener.new(query.name, @output_pool)
|
365
|
+
epl.java_send :addListener, [com.espertech.esper.client.UpdateListener.java_class], Listener.new(query.name, query.group, @output_pool)
|
361
366
|
query.statement_name = epl.getName
|
362
367
|
# epl is automatically started.
|
363
368
|
# epl.isStarted #=> true
|
data/lib/norikra/error.rb
CHANGED
data/lib/norikra/output_pool.rb
CHANGED
@@ -1,9 +1,12 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
1
3
|
module Norikra
|
2
4
|
class OutputPool
|
3
5
|
attr_accessor :pool
|
4
6
|
|
5
7
|
def initialize
|
6
|
-
@pool = {}
|
8
|
+
@pool = {} # { query_name => [events] }
|
9
|
+
@groups = {} # { group_name => Set(query_names) }
|
7
10
|
@mutex = Mutex.new
|
8
11
|
end
|
9
12
|
|
@@ -11,10 +14,19 @@ module Norikra
|
|
11
14
|
@pool.keys
|
12
15
|
end
|
13
16
|
|
14
|
-
def push(query_name, events)
|
17
|
+
def push(query_name, query_group, events) # events must be [time(int), event_record]
|
18
|
+
# called with blank events for window leavings (and/or other situations)
|
19
|
+
return if events.size < 1
|
20
|
+
|
15
21
|
@mutex.synchronize do
|
22
|
+
if @groups[query_group]
|
23
|
+
@groups[query_group].add(query_name) # Set is unique set of elements
|
24
|
+
else
|
25
|
+
@groups[query_group] ||= Set.new([query_name])
|
26
|
+
end
|
27
|
+
|
16
28
|
@pool[query_name] ||= []
|
17
|
-
@pool[query_name].push(events)
|
29
|
+
@pool[query_name].push(events)
|
18
30
|
end
|
19
31
|
end
|
20
32
|
|
@@ -27,11 +39,15 @@ module Norikra
|
|
27
39
|
end
|
28
40
|
|
29
41
|
# returns {query_name => [[time, event], ...]}
|
30
|
-
def sweep
|
42
|
+
def sweep(group=nil)
|
43
|
+
return {} if @groups[group].nil?
|
44
|
+
|
31
45
|
ret = {}
|
32
46
|
sweep_pool = @mutex.synchronize do
|
33
|
-
sweeped =
|
34
|
-
@
|
47
|
+
sweeped = {}
|
48
|
+
@groups[group].each do |qname|
|
49
|
+
sweeped[qname] = @pool.delete(qname) if @pool[qname] && @pool[qname].size > 0
|
50
|
+
end
|
35
51
|
sweeped
|
36
52
|
end
|
37
53
|
sweep_pool.keys.each do |k|
|
data/lib/norikra/query.rb
CHANGED
@@ -9,10 +9,11 @@ require 'norikra/query/ast'
|
|
9
9
|
|
10
10
|
module Norikra
|
11
11
|
class Query
|
12
|
-
attr_accessor :name, :expression, :statement_name, :fieldsets
|
12
|
+
attr_accessor :name, :group, :expression, :statement_name, :fieldsets
|
13
13
|
|
14
14
|
def initialize(param={})
|
15
15
|
@name = param[:name]
|
16
|
+
@group = param[:group] # default nil
|
16
17
|
@expression = param[:expression]
|
17
18
|
@statement_name = nil
|
18
19
|
@fieldsets = {} # { target => fieldset }
|
@@ -23,7 +24,7 @@ module Norikra
|
|
23
24
|
end
|
24
25
|
|
25
26
|
def dup
|
26
|
-
self.class.new(:name => @name, :expression => @expression.dup)
|
27
|
+
self.class.new(:name => @name, :group => @group, :expression => @expression.dup)
|
27
28
|
end
|
28
29
|
|
29
30
|
def dup_with_stream_name(actual_name)
|
@@ -37,7 +38,7 @@ module Norikra
|
|
37
38
|
end
|
38
39
|
|
39
40
|
def to_hash
|
40
|
-
{'name' => @name, 'expression' => @expression, 'targets' => self.targets}
|
41
|
+
{'name' => @name, 'group' => @group, 'expression' => @expression, 'targets' => self.targets}
|
41
42
|
end
|
42
43
|
|
43
44
|
def targets
|
data/lib/norikra/rpc/handler.rb
CHANGED
@@ -56,9 +56,9 @@ class Norikra::RPC::Handler
|
|
56
56
|
}
|
57
57
|
end
|
58
58
|
|
59
|
-
def register(query_name, expression)
|
60
|
-
logging(:manage, :register, query_name, expression){
|
61
|
-
r = @engine.register(Norikra::Query.new(:name => query_name, :expression => expression))
|
59
|
+
def register(query_name, query_group, expression)
|
60
|
+
logging(:manage, :register, query_name, query_group, expression){
|
61
|
+
r = @engine.register(Norikra::Query.new(:name => query_name, :group => query_group, :expression => expression))
|
62
62
|
!!r
|
63
63
|
}
|
64
64
|
end
|
@@ -96,9 +96,9 @@ class Norikra::RPC::Handler
|
|
96
96
|
}
|
97
97
|
end
|
98
98
|
|
99
|
-
def sweep
|
99
|
+
def sweep(query_group=nil)
|
100
100
|
logging(:show, :sweep){
|
101
|
-
@engine.output_pool.sweep
|
101
|
+
@engine.output_pool.sweep(query_group)
|
102
102
|
}
|
103
103
|
end
|
104
104
|
|
data/lib/norikra/rpc/http.rb
CHANGED
@@ -6,14 +6,20 @@ require_relative 'handler'
|
|
6
6
|
|
7
7
|
module Norikra::RPC
|
8
8
|
class HTTP
|
9
|
-
|
9
|
+
DEFAULT_LISTEN_HOST = '0.0.0.0'
|
10
|
+
DEFAULT_LISTEN_PORT = 26571
|
11
|
+
# 26571 = 3026 + 3014 + 2968 + 2950 + 2891 + 2896 + 2975 + 2979 + 2872
|
12
|
+
|
13
|
+
DEFAULT_THREADS = 2
|
14
|
+
|
10
15
|
attr_accessor :host, :port, :threads
|
11
16
|
attr_accessor :engine, :mizuno, :thread
|
12
17
|
|
13
18
|
def initialize(opts={})
|
14
19
|
@engine = opts[:engine]
|
15
|
-
@host = opts[:host]
|
16
|
-
@port = opts[:port]
|
20
|
+
@host = opts[:host] || DEFAULT_LISTEN_HOST
|
21
|
+
@port = opts[:port] || DEFAULT_LISTEN_PORT
|
22
|
+
@threads = opts[:threads] || DEFAULT_THREADS
|
17
23
|
handler = Norikra::RPC::Handler.new(@engine)
|
18
24
|
@app = Rack::Builder.new {
|
19
25
|
run MessagePack::RPCOverHTTP::Server.app(handler)
|
@@ -23,7 +29,7 @@ module Norikra::RPC
|
|
23
29
|
def start
|
24
30
|
@thread = Thread.new do
|
25
31
|
@mizuno = Mizuno::Server.new
|
26
|
-
@mizuno.run(@app, :embedded => true, :threads =>
|
32
|
+
@mizuno.run(@app, :embedded => true, :threads => @threads, :port => @port, :host => @host)
|
27
33
|
end
|
28
34
|
end
|
29
35
|
|
data/lib/norikra/rubyudf.rb
CHANGED
@@ -1,49 +1,49 @@
|
|
1
1
|
# this is note for future update
|
2
2
|
|
3
|
-
module Norikra
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
end
|
3
|
+
# module Norikra
|
4
|
+
# module UDF
|
5
|
+
# class FailedUDFImplementationPureRuby
|
6
|
+
# # require 'jruby/core_ext'
|
7
|
+
# class WootheeIsCrawler < Norikra::UDF::Base # Norikra::UDF::WootheeIsCrawler < Norikra::UDF::Base
|
8
|
+
# def self.init
|
9
|
+
# require 'woothee'
|
10
|
+
# end
|
11
|
+
|
12
|
+
# def self.function_name
|
13
|
+
# "isCrawler"
|
14
|
+
# end
|
15
|
+
|
16
|
+
# def self.isCrawler(agent)
|
17
|
+
# Woothee.is_crawler(agent)
|
18
|
+
# end
|
19
|
+
# class << self
|
20
|
+
# add_method_signature( "isCrawler", [java.lang.Boolean, java.lang.String] )
|
21
|
+
# end
|
22
|
+
# end
|
23
|
+
|
24
|
+
# # for engine.rb
|
25
|
+
# def load_udf_actually(udf_klass)
|
26
|
+
# require 'jruby/core_ext'
|
27
|
+
# udf_klass.init
|
28
|
+
|
29
|
+
# jclass = udf_klass.become_java!(".")
|
30
|
+
# className = jclass.get_name.to_java(:string)
|
31
|
+
|
32
|
+
# #### try for NullPointerException, but doesn't work well
|
33
|
+
# # field = jclass.getDeclaredField("ruby");
|
34
|
+
# # field.setAccessible(java.lang.Boolean::TRUE)
|
35
|
+
# # field.set(nil, org.jruby.Ruby.getGlobalRuntime)
|
36
|
+
|
37
|
+
# functionName = udf_klass.function_name.to_java(:string)
|
38
|
+
# methodName = udf_klass.method_name.to_java(:string)
|
39
|
+
|
40
|
+
# valueCache = udf_klass.value_cache ? VALUE_CACHE_ENUM::ENABLED : VALUE_CACHE_ENUM::DISABLED
|
41
|
+
# filterOptimizable = udf_klass.filter_optimizable ? FILTER_OPTIMIZABLE_ENUM::ENABLED : FILTER_OPTIMIZABLE_ENUM::DISABLED
|
42
|
+
# rethrowExceptions = udf_klass.rethrow_exceptions
|
43
|
+
|
44
|
+
# debug "adding SingleRowFunction", :class => udf_klass.to_s, :javaClass => jclass.get_name
|
45
|
+
# @config.addPlugInSingleRowFunction(functionName, className, methodName, valueCache, filterOptimizable, rethrowExceptions)
|
46
|
+
# end
|
47
|
+
# end
|
48
|
+
# end
|
49
|
+
# end
|
data/lib/norikra/server.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'norikra/engine'
|
2
2
|
|
3
|
+
require 'norikra/stats'
|
3
4
|
require 'norikra/logger'
|
4
5
|
include Norikra::Log
|
5
6
|
|
@@ -13,29 +14,102 @@ require 'norikra/udf'
|
|
13
14
|
|
14
15
|
module Norikra
|
15
16
|
class Server
|
16
|
-
RPC_DEFAULT_HOST = '0.0.0.0'
|
17
|
-
RPC_DEFAULT_PORT = 26571
|
18
|
-
# 26571 = 3026 + 3014 + 2968 + 2950 + 2891 + 2896 + 2975 + 2979 + 2872
|
19
|
-
|
20
17
|
attr_accessor :running
|
21
18
|
|
22
|
-
|
23
|
-
|
19
|
+
MICRO_PREDEFINED = {
|
20
|
+
:engine => { inbound: { threads: 0, capacity: 0 }, outbound: { threads: 0, capacity: 0 },
|
21
|
+
route_exec: { threads: 0, capacity: 0 }, timer_exec: { threads: 0, capacity: 0 }, },
|
22
|
+
:rpc => { threads: 2 },
|
23
|
+
}
|
24
|
+
SMALL_PREDEFINED = {
|
25
|
+
:engine => { inbound: { threads: 1, capacity: 0 }, outbound: { threads: 1, capacity: 0 },
|
26
|
+
route_exec: { threads: 1, capacity: 0 }, timer_exec: { threads: 1, capacity: 0 }, },
|
27
|
+
:rpc => { threads: 2 },
|
28
|
+
}
|
29
|
+
MIDDLE_PREDEFINED = {
|
30
|
+
:engine => { inbound: { threads: 4, capacity: 0 }, outbound: { threads: 2, capacity: 0 },
|
31
|
+
route_exec: { threads: 2, capacity: 0 }, timer_exec: { threads: 2, capacity: 0 }, },
|
32
|
+
:rpc => { threads: 4 },
|
33
|
+
}
|
34
|
+
LARGE_PREDEFINED = {
|
35
|
+
:engine => { inbound: { threads: 6, capacity: 0 }, outbound: { threads: 6, capacity: 0 },
|
36
|
+
route_exec: { threads: 4, capacity: 0 }, timer_exec: { threads: 4, capacity: 0 }, },
|
37
|
+
:rpc => { threads: 8 },
|
38
|
+
}
|
39
|
+
|
40
|
+
def self.threading_configuration(conf, stats)
|
41
|
+
threads = case conf[:predefined]
|
42
|
+
when :micro then MICRO_PREDEFINED
|
43
|
+
when :small then SMALL_PREDEFINED
|
44
|
+
when :middle then MIDDLE_PREDEFINED
|
45
|
+
when :large then LARGE_PREDEFINED
|
46
|
+
else (stats ? stats.threads : MICRO_PREDEFINED)
|
47
|
+
end
|
48
|
+
[:inbound, :outbound, :route_exec, :timer_exec].each do |type|
|
49
|
+
[:threads, :capacity].each do |item|
|
50
|
+
threads[:engine][type][item] = conf[:engine][type][item] if conf[:engine][type][item]
|
51
|
+
end
|
52
|
+
end
|
53
|
+
threads[:rpc][:threads] = conf[:rpc][:threads] if conf[:rpc][:threads]
|
54
|
+
threads
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.log_configuration(conf, stats)
|
58
|
+
logconf = stats ? stats.log : { level: nil, dir: nil, filesize: nil, backups: nil }
|
59
|
+
[:level, :dir, :filesize, :backups].each do |sym|
|
60
|
+
logconf[sym] = conf[sym] if conf[sym]
|
61
|
+
end
|
62
|
+
logconf
|
63
|
+
end
|
64
|
+
|
65
|
+
def initialize(host, port, conf={})
|
66
|
+
@stats_path = conf[:stats][:path]
|
67
|
+
@stats_suppress_dump = conf[:stats][:suppress]
|
68
|
+
@stats = if @stats_path && test(?r, @stats_path)
|
69
|
+
Norikra::Stats.load(@stats_path)
|
70
|
+
else
|
71
|
+
nil
|
72
|
+
end
|
73
|
+
|
74
|
+
@host = host || (@stats ? @stats.host : nil)
|
75
|
+
@port = port || (@stats ? @stats.port : nil)
|
76
|
+
|
77
|
+
@thread_conf = self.class.threading_configuration(conf[:thread], @stats)
|
78
|
+
@log_conf = self.class.log_configuration(conf[:log], @stats)
|
79
|
+
|
80
|
+
Norikra::Log.init(@log_conf[:level], @log_conf[:dir], {:filesize => @log_conf[:filesize], :backups => @log_conf[:backups]})
|
81
|
+
|
82
|
+
info "thread configurations", @thread_conf
|
83
|
+
info "logging configurations", @log_conf
|
84
|
+
|
24
85
|
@typedef_manager = Norikra::TypedefManager.new
|
25
86
|
@output_pool = Norikra::OutputPool.new
|
26
87
|
|
27
|
-
Norikra::
|
28
|
-
|
29
|
-
@engine = Norikra::Engine.new(@output_pool, @typedef_manager, {thread: conf[:thread]})
|
30
|
-
@rpcserver = Norikra::RPC::HTTP.new(:engine => @engine, :port => port)
|
88
|
+
@engine = Norikra::Engine.new(@output_pool, @typedef_manager, {thread: @thread_conf[:engine]})
|
89
|
+
@rpcserver = Norikra::RPC::HTTP.new(:engine => @engine, :host => @host, :port => @port, :threads => @thread_conf[:rpc][:threads])
|
31
90
|
end
|
32
91
|
|
33
92
|
def run
|
34
93
|
@engine.start
|
35
|
-
@rpcserver.start
|
36
94
|
|
37
95
|
load_plugins
|
38
96
|
|
97
|
+
if @stats
|
98
|
+
info "loading from stats file"
|
99
|
+
if @stats.targets && @stats.targets.size > 0
|
100
|
+
@stats.targets.each do |target|
|
101
|
+
@engine.open(target[:name], target[:fields])
|
102
|
+
end
|
103
|
+
end
|
104
|
+
if @stats.queries && @stats.queries.size > 0
|
105
|
+
@stats.queries.each do |query|
|
106
|
+
@engine.register(Norikra::Query.new(:name => query[:name], :expression => query[:expression]))
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
@rpcserver.start
|
112
|
+
|
39
113
|
@running = true
|
40
114
|
info "Norikra server started."
|
41
115
|
|
@@ -71,6 +145,21 @@ module Norikra
|
|
71
145
|
info "Norikra server shutting down."
|
72
146
|
@rpcserver.stop
|
73
147
|
@engine.stop
|
148
|
+
info "Norikra server stopped."
|
149
|
+
|
150
|
+
if @stats_path && !@stats_suppress_dump
|
151
|
+
stats = Norikra::Stats.new(
|
152
|
+
host: @host,
|
153
|
+
port: @port,
|
154
|
+
threads: @thread_conf,
|
155
|
+
log: @log_conf,
|
156
|
+
targets: @engine.typedef_manager.dump,
|
157
|
+
queries: @engine.queries.map{|q| {:name => q.name, :expression => q.expression}}
|
158
|
+
)
|
159
|
+
stats.dump(@stats_path)
|
160
|
+
info "Current status saved", :path => @stats_path
|
161
|
+
end
|
162
|
+
|
74
163
|
info "Norikra server shutdown complete."
|
75
164
|
end
|
76
165
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Norikra
|
4
|
+
class Stats
|
5
|
+
attr_accessor :host, :port, :threads, :log
|
6
|
+
attr_accessor :targets, :queries
|
7
|
+
|
8
|
+
def initialize(opts={})
|
9
|
+
@host = opts[:host]
|
10
|
+
@port = opts[:port]
|
11
|
+
@threads = opts[:threads]
|
12
|
+
@log = opts[:log]
|
13
|
+
@targets = opts[:targets] || []
|
14
|
+
@queries = opts[:queries] || []
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_hash
|
18
|
+
{host: @host, port: @port, threads: @threads, log: @log, targets: @targets, queries: @queries}
|
19
|
+
end
|
20
|
+
|
21
|
+
def dump(path)
|
22
|
+
File.open(path, 'w') do |file|
|
23
|
+
file.write(JSON.pretty_generate(self.to_hash))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.load(path)
|
28
|
+
File.open(path, 'r') do |file|
|
29
|
+
self.new(JSON.parse(file.read, symbolize_names: true))
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/norikra/typedef.rb
CHANGED
@@ -15,8 +15,12 @@ module Norikra
|
|
15
15
|
@optional = optional
|
16
16
|
end
|
17
17
|
|
18
|
-
def to_hash
|
19
|
-
|
18
|
+
def to_hash(sym=false)
|
19
|
+
if sym
|
20
|
+
{name: @name, type: @type, optional: @optional}
|
21
|
+
else
|
22
|
+
{'name' => @name, 'type' => @type, 'optional' => @optional}
|
23
|
+
end
|
20
24
|
end
|
21
25
|
|
22
26
|
def dup(optional=nil)
|
@@ -55,7 +59,7 @@ module Norikra
|
|
55
59
|
when 'float' then 'float'
|
56
60
|
when 'double' then 'double'
|
57
61
|
else
|
58
|
-
raise Norikra::ArgumentError, "invalid field type #{type}"
|
62
|
+
raise Norikra::ArgumentError, "invalid field type '#{type}'"
|
59
63
|
end
|
60
64
|
end
|
61
65
|
|
@@ -80,13 +84,13 @@ module Norikra
|
|
80
84
|
fields.keys.each do |key|
|
81
85
|
data = fields[key]
|
82
86
|
type,optional = if data.is_a?(Hash)
|
83
|
-
[data[:type], (data.has_key?(:optional) ? data[:optional] : default_optional)]
|
84
|
-
elsif data.is_a?(String)
|
85
|
-
[data, default_optional]
|
87
|
+
[data[:type].to_s, (data.has_key?(:optional) ? data[:optional] : default_optional)]
|
88
|
+
elsif data.is_a?(String) || data.is_a?(Symbol)
|
89
|
+
[data.to_s, default_optional]
|
86
90
|
else
|
87
91
|
raise ArgumentError, "FieldSet.new argument class unknown: #{fields.class}"
|
88
92
|
end
|
89
|
-
@fields[key.to_s] = Field.new(key, type, optional)
|
93
|
+
@fields[key.to_s] = Field.new(key.to_s, type, optional)
|
90
94
|
end
|
91
95
|
self.update_summary
|
92
96
|
|
@@ -366,5 +370,13 @@ module Norikra
|
|
366
370
|
end
|
367
371
|
ret
|
368
372
|
end
|
373
|
+
|
374
|
+
def dump
|
375
|
+
fields = {}
|
376
|
+
@fields.map{|key,field|
|
377
|
+
fields[key.to_sym] = field.to_hash(true)
|
378
|
+
}
|
379
|
+
fields
|
380
|
+
end
|
369
381
|
end
|
370
382
|
end
|
data/lib/norikra/version.rb
CHANGED
data/norikra.gemspec
CHANGED
@@ -23,7 +23,7 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.add_runtime_dependency "rack"
|
24
24
|
spec.add_runtime_dependency "msgpack-rpc-over-http-jruby", ">= 0.0.5"
|
25
25
|
spec.add_runtime_dependency "thor"
|
26
|
-
spec.add_runtime_dependency "norikra-client-jruby", ">= 0.0.
|
26
|
+
spec.add_runtime_dependency "norikra-client-jruby", ">= 0.0.6"
|
27
27
|
|
28
28
|
spec.add_development_dependency "bundler", "~> 1.3"
|
29
29
|
spec.add_development_dependency "rake"
|
data/spec/output_pool_spec.rb
CHANGED
@@ -12,15 +12,18 @@ describe Norikra::OutputPool do
|
|
12
12
|
|
13
13
|
describe '#push' do
|
14
14
|
context 'with empty array' do
|
15
|
-
|
16
|
-
|
15
|
+
it 'will be ignored' do
|
16
|
+
p = Norikra::OutputPool.new
|
17
|
+
p.push('TestTable query1', nil, [])
|
18
|
+
expect(p.pool).to eql({})
|
19
|
+
end
|
17
20
|
end
|
18
21
|
|
19
22
|
context 'with event array' do
|
20
23
|
it 'has pool with event' do
|
21
24
|
pool = Norikra::OutputPool.new
|
22
25
|
t = Time.now.to_i
|
23
|
-
pool.push('TestTable query1',
|
26
|
+
pool.push('TestTable query1',nil,[[t, {'count'=>1}],[t ,{'count'=>2}]])
|
24
27
|
|
25
28
|
pool.pool.keys.should eql(['TestTable query1'])
|
26
29
|
events = pool.pool['TestTable query1']
|
@@ -46,8 +49,8 @@ describe Norikra::OutputPool do
|
|
46
49
|
it 'returns all events of specified query in pool' do
|
47
50
|
pool = Norikra::OutputPool.new
|
48
51
|
t = Time.now.to_i
|
49
|
-
pool.push('TestTable query1', [{'count'=>1},{'count'=>2}])
|
50
|
-
pool.push('TestTable query2', [{'count'=>3},{'count'=>4}])
|
52
|
+
pool.push('TestTable query1', nil, [[t,{'count'=>1}],[t,{'count'=>2}]])
|
53
|
+
pool.push('TestTable query2', nil, [[t,{'count'=>3}],[t,{'count'=>4}]])
|
51
54
|
|
52
55
|
expect(pool.pop('TestTable query0').size).to eql(0)
|
53
56
|
expect(pool.pop('TestTable query1').size).to eql(2)
|
@@ -57,18 +60,42 @@ describe Norikra::OutputPool do
|
|
57
60
|
end
|
58
61
|
|
59
62
|
describe '#sweep' do
|
60
|
-
|
61
|
-
pool
|
62
|
-
|
63
|
-
|
64
|
-
|
63
|
+
context 'with default query group' do
|
64
|
+
it 'returns all events for all queries in pool' do
|
65
|
+
pool = Norikra::OutputPool.new
|
66
|
+
t = Time.now.to_i
|
67
|
+
pool.push('TestTable query1', nil, [[t,{'count'=>1}],[t,{'count'=>2}]])
|
68
|
+
pool.push('TestTable query2', nil, [[t,{'count'=>3}],[t,{'count'=>4}],[t,{'count'=>5}]])
|
69
|
+
pool.push('TestTable query3', 'x', [[t,{'count'=>3}],[t,{'count'=>4}],[t,{'count'=>5}]])
|
65
70
|
|
66
|
-
|
67
|
-
|
71
|
+
chunk = pool.sweep
|
72
|
+
expect(chunk.keys.size).to eql(2)
|
68
73
|
|
69
|
-
|
70
|
-
|
71
|
-
|
74
|
+
expect(chunk['TestTable query1'].size).to eql(2)
|
75
|
+
expect(chunk['TestTable query2'].size).to eql(3)
|
76
|
+
expect(chunk['TestTable query2'].last.last['count']).to eql(5)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context 'with group specified' do
|
81
|
+
it 'returns all events for all queries in pool' do
|
82
|
+
pool = Norikra::OutputPool.new
|
83
|
+
t = Time.now.to_i
|
84
|
+
pool.push('TestTable query1', nil, [[t,{'count'=>1}],[t,{'count'=>2}]])
|
85
|
+
pool.push('TestTable query2', nil, [[t,{'count'=>3}],[t,{'count'=>4}],[t,{'count'=>5}]])
|
86
|
+
pool.push('TestTable query3', 'x', [[t,{'count'=>3}],[t,{'count'=>4}],[t,{'count'=>5}]])
|
87
|
+
pool.push('TestTable query4', 'y', [[t,{'count'=>1}],[t,{'count'=>2}]])
|
88
|
+
pool.push('TestTable query5', 'x', [[t,{'count'=>9}]])
|
89
|
+
pool.push('TestTable query6', 'x', [[t,{'count'=>3}],[t,{'count'=>4}],[t,{'count'=>5}]])
|
90
|
+
pool.push('TestTable query6', 'x', [[t,{'count'=>6}],[t,{'count'=>7}]])
|
91
|
+
|
92
|
+
chunk = pool.sweep('x')
|
93
|
+
expect(chunk.keys.size).to eql(3)
|
94
|
+
|
95
|
+
expect(chunk['TestTable query3'].size).to eql(3)
|
96
|
+
expect(chunk['TestTable query5'].size).to eql(1)
|
97
|
+
expect(chunk['TestTable query6'].size).to eql(5)
|
98
|
+
end
|
72
99
|
end
|
73
100
|
end
|
74
101
|
end
|
data/spec/query_spec.rb
CHANGED
@@ -12,6 +12,7 @@ describe Norikra::Query do
|
|
12
12
|
:name => 'TestTable query1', :expression => expression
|
13
13
|
)
|
14
14
|
expect(q.name).to eql('TestTable query1')
|
15
|
+
expect(q.group).to be_nil
|
15
16
|
expect(q.expression).to eql(expression)
|
16
17
|
expect(q.targets).to eql(['TestTable'])
|
17
18
|
|
@@ -25,9 +26,10 @@ describe Norikra::Query do
|
|
25
26
|
it 'returns query instances collectly parsed' do
|
26
27
|
expression = 'SELECT count(*) AS cnt FROM TestTable.win:time_batch(10 sec) AS source WHERE source.path="/" AND Math.abs(-1 * source.size) > 3'
|
27
28
|
q = Norikra::Query.new(
|
28
|
-
:name => 'TestTable query2', :expression => expression
|
29
|
+
:name => 'TestTable query2', :group => 'label1', :expression => expression
|
29
30
|
)
|
30
31
|
expect(q.name).to eql('TestTable query2')
|
32
|
+
expect(q.group).to eql('label1')
|
31
33
|
expect(q.expression).to eql(expression)
|
32
34
|
expect(q.targets).to eql(['TestTable'])
|
33
35
|
|
@@ -106,7 +108,31 @@ describe Norikra::Query do
|
|
106
108
|
end
|
107
109
|
end
|
108
110
|
|
109
|
-
|
111
|
+
describe '#dup' do
|
112
|
+
context 'for queries without group (default group)' do
|
113
|
+
it 'returns query object with default group' do
|
114
|
+
e1 = 'SELECT max(num) AS max FROM TestTable1.win:time(5 sec)'
|
115
|
+
query = Norikra::Query.new(:name => 'q1', :group => nil, :expression => e1)
|
116
|
+
q = query.dup
|
117
|
+
expect(q.name).to eql('q1')
|
118
|
+
expect(q.group).to be_nil
|
119
|
+
expect(q.expression).to eql(e1)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
context 'for queries with group' do
|
124
|
+
it 'returns query object with specified group' do
|
125
|
+
e2 = 'SELECT max(num) AS max FROM TestTable2.win:time(5 sec)'
|
126
|
+
query = Norikra::Query.new(:name => 'q2', :group => 'g2', :expression => e2)
|
127
|
+
q = query.dup
|
128
|
+
expect(q.name).to eql('q2')
|
129
|
+
expect(q.group).to eql('g2')
|
130
|
+
expect(q.expression).to eql(e2)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
describe '#dup_with_stream_name' do
|
110
136
|
context 'with simple query' do
|
111
137
|
expression = 'SELECT count(*) AS cnt FROM TestTable.win:time_batch(10 sec) WHERE path="/" AND size > 100 and param.length() > 0'
|
112
138
|
it 'returns duplicated object, with replaced ' do
|
data/spec/stats_spec.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require_relative './spec_helper'
|
2
|
+
|
3
|
+
require 'norikra/stats'
|
4
|
+
require 'norikra/server'
|
5
|
+
|
6
|
+
require 'tmpdir'
|
7
|
+
|
8
|
+
describe Norikra::Stats do
|
9
|
+
describe '#to_hash' do
|
10
|
+
it 'returns internal stats as hash with symbolized keys' do
|
11
|
+
args = {
|
12
|
+
host: nil,
|
13
|
+
port: nil,
|
14
|
+
threads: Norikra::Server::SMALL_PREDEFINED,
|
15
|
+
log: {level: nil, dir: nil, filesize: nil, backups: nil},
|
16
|
+
targets: [],
|
17
|
+
queries: [],
|
18
|
+
}
|
19
|
+
s = Norikra::Stats.new(args)
|
20
|
+
expect(s.to_hash).to eql(args)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '.load' do
|
25
|
+
it 'can restore stats data from #dump -ed json' do
|
26
|
+
Dir.mktmpdir do |dir|
|
27
|
+
File.open("#{dir}/stats.json", 'w') do |file|
|
28
|
+
args = {
|
29
|
+
host: nil,
|
30
|
+
port: nil,
|
31
|
+
threads: Norikra::Server::LARGE_PREDEFINED,
|
32
|
+
log: {level: 'WARN', dir: '/var/log/norikra', filesize: '50MB', backups: 300},
|
33
|
+
targets: [
|
34
|
+
{ name: 'test1', fields: { id: { name: 'id', type: 'int', optional: false}, data: { name: 'data', type: 'string', optional: true } } },
|
35
|
+
],
|
36
|
+
queries: [
|
37
|
+
{ name: 'testq2', expression: 'select count(*) from test1.win:time(5 sec)' },
|
38
|
+
{ name: 'testq1', expression: 'select count(*) from test1.win:time(10 sec)' },
|
39
|
+
],
|
40
|
+
}
|
41
|
+
s1 = Norikra::Stats.new(args)
|
42
|
+
expect(s1.to_hash).to eql(args)
|
43
|
+
|
44
|
+
s1.dump(file.path)
|
45
|
+
|
46
|
+
s2 = Norikra::Stats.load(file.path)
|
47
|
+
expect(s2.to_hash).to eql(s1.to_hash)
|
48
|
+
expect(s2.to_hash).to eql(args)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/spec/target_spec.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require_relative './spec_helper'
|
2
|
+
|
3
|
+
require 'norikra/target'
|
4
|
+
# require 'norikra/error'
|
5
|
+
|
6
|
+
describe Norikra::Target do
|
7
|
+
describe '.valid?' do
|
8
|
+
it 'raises Norikra::ArgumentError for invalid name' do
|
9
|
+
expect(Norikra::Target.valid?('foobar')).to be_true
|
10
|
+
expect(Norikra::Target.valid?('FooBar')).to be_true
|
11
|
+
expect(Norikra::Target.valid?('foo_bar')).to be_true
|
12
|
+
expect(Norikra::Target.valid?('foo_bar_baz')).to be_true
|
13
|
+
|
14
|
+
expect(Norikra::Target.valid?('')).to be_false
|
15
|
+
expect(Norikra::Target.valid?('.')).to be_false
|
16
|
+
expect(Norikra::Target.valid?('_')).to be_false
|
17
|
+
expect(Norikra::Target.valid?('_a_')).to be_false
|
18
|
+
expect(Norikra::Target.valid?('foo_')).to be_false
|
19
|
+
expect(Norikra::Target.valid?('_Foo')).to be_false
|
20
|
+
expect(Norikra::Target.valid?('foo bar')).to be_false
|
21
|
+
expect(Norikra::Target.valid?('_Foo')).to be_false
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -200,5 +200,31 @@ describe Norikra::TypedefManager do
|
|
200
200
|
expect(r.summary).to eql('a:string,b:string,c:double,f:boolean')
|
201
201
|
end
|
202
202
|
end
|
203
|
+
|
204
|
+
describe '#dump' do
|
205
|
+
it 'returns array of target typedef dump' do
|
206
|
+
m = Norikra::TypedefManager.new
|
207
|
+
m.add_target('sample', {'a'=>'string','b'=>'string','c'=>'double'})
|
208
|
+
m.reserve('sample', 'z', 'boolean')
|
209
|
+
m.add_target('sample_next', {'a'=>'string','b'=>'string','c'=>'double','d'=>'double'})
|
210
|
+
|
211
|
+
r = m.dump
|
212
|
+
expect(r.size).to eql(2)
|
213
|
+
expect(r[0][:name]).to eql('sample')
|
214
|
+
expect(r[0][:fields]).to eql({
|
215
|
+
a: {name: 'a', type: 'string', optional: false},
|
216
|
+
b: {name: 'b', type: 'string', optional: false},
|
217
|
+
c: {name: 'c', type: 'double', optional: false},
|
218
|
+
z: {name: 'z', type: 'boolean', optional: true},
|
219
|
+
})
|
220
|
+
expect(r[1][:name]).to eql('sample_next')
|
221
|
+
expect(r[1][:fields]).to eql({
|
222
|
+
a: {name: 'a', type: 'string', optional: false},
|
223
|
+
b: {name: 'b', type: 'string', optional: false},
|
224
|
+
c: {name: 'c', type: 'double', optional: false},
|
225
|
+
d: {name: 'd', type: 'double', optional: false},
|
226
|
+
})
|
227
|
+
end
|
228
|
+
end
|
203
229
|
end
|
204
230
|
end
|
data/spec/typedef_spec.rb
CHANGED
@@ -296,5 +296,27 @@ describe Norikra::Typedef do
|
|
296
296
|
expect(d['d']).to eql(3.14)
|
297
297
|
end
|
298
298
|
end
|
299
|
+
|
300
|
+
describe '#dump' do
|
301
|
+
it 'returns hash instance to show fields and its types/optionals' do
|
302
|
+
t = Norikra::Typedef.new({'a'=>'string','b'=>'long'})
|
303
|
+
t.push(:query, Norikra::FieldSet.new({'a'=>'string','b'=>'long'}))
|
304
|
+
t.push(:data, Norikra::FieldSet.new({'a'=>'string','b'=>'long'}))
|
305
|
+
t.push(:data, Norikra::FieldSet.new({'a'=>'string','b'=>'long','c'=>'double'}))
|
306
|
+
t.push(:query, Norikra::FieldSet.new({'a'=>'string','b'=>'long','d'=>'string'}))
|
307
|
+
fields = t.fields
|
308
|
+
|
309
|
+
r = t.dump
|
310
|
+
expect(r.keys.sort).to eql([:a, :b, :c, :d])
|
311
|
+
expect(r[:a]).to eql({name: 'a', type: 'string', optional: false})
|
312
|
+
expect(r[:b]).to eql({name: 'b', type: 'long', optional: false})
|
313
|
+
expect(r[:c]).to eql({name: 'c', type: 'double', optional: true})
|
314
|
+
expect(r[:d]).to eql({name: 'd', type: 'string', optional: true})
|
315
|
+
|
316
|
+
t2 = Norikra::Typedef.new(r)
|
317
|
+
expect(t2.fields.keys.sort).to eql(fields.keys.sort)
|
318
|
+
expect(t2.fields.values.map(&:to_hash)).to eql(fields.values.map(&:to_hash))
|
319
|
+
end
|
320
|
+
end
|
299
321
|
end
|
300
322
|
end
|
metadata
CHANGED
@@ -2,14 +2,14 @@
|
|
2
2
|
name: norikra
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.0.
|
5
|
+
version: 0.0.12
|
6
6
|
platform: java
|
7
7
|
authors:
|
8
8
|
- TAGOMORI Satoshi
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-09-03 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: mizuno
|
@@ -81,13 +81,13 @@ dependencies:
|
|
81
81
|
requirements:
|
82
82
|
- - '>='
|
83
83
|
- !ruby/object:Gem::Version
|
84
|
-
version: 0.0.
|
84
|
+
version: 0.0.6
|
85
85
|
none: false
|
86
86
|
requirement: !ruby/object:Gem::Requirement
|
87
87
|
requirements:
|
88
88
|
- - '>='
|
89
89
|
- !ruby/object:Gem::Version
|
90
|
-
version: 0.0.
|
90
|
+
version: 0.0.6
|
91
91
|
none: false
|
92
92
|
prerelease: false
|
93
93
|
type: :runtime
|
@@ -183,6 +183,7 @@ extra_rdoc_files: []
|
|
183
183
|
files:
|
184
184
|
- .gitignore
|
185
185
|
- .ruby-version
|
186
|
+
- .travis.yml
|
186
187
|
- Gemfile
|
187
188
|
- LICENSE
|
188
189
|
- README.md
|
@@ -274,6 +275,8 @@ files:
|
|
274
275
|
- lib/norikra/rpc/http.rb
|
275
276
|
- lib/norikra/rubyudf.rb
|
276
277
|
- lib/norikra/server.rb
|
278
|
+
- lib/norikra/stats.rb
|
279
|
+
- lib/norikra/target.rb
|
277
280
|
- lib/norikra/typedef.rb
|
278
281
|
- lib/norikra/typedef_manager.rb
|
279
282
|
- lib/norikra/udf.rb
|
@@ -286,6 +289,8 @@ files:
|
|
286
289
|
- spec/output_pool_spec.rb
|
287
290
|
- spec/query_spec.rb
|
288
291
|
- spec/spec_helper.rb
|
292
|
+
- spec/stats_spec.rb
|
293
|
+
- spec/target_spec.rb
|
289
294
|
- spec/typedef_manager_spec.rb
|
290
295
|
- spec/typedef_spec.rb
|
291
296
|
homepage: https://github.com/tagomoris/norikra
|
@@ -300,12 +305,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
300
305
|
requirements:
|
301
306
|
- - '>='
|
302
307
|
- !ruby/object:Gem::Version
|
308
|
+
segments:
|
309
|
+
- 0
|
310
|
+
hash: 2
|
303
311
|
version: '0'
|
304
312
|
none: false
|
305
313
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
306
314
|
requirements:
|
307
315
|
- - '>='
|
308
316
|
- !ruby/object:Gem::Version
|
317
|
+
segments:
|
318
|
+
- 0
|
319
|
+
hash: 2
|
309
320
|
version: '0'
|
310
321
|
none: false
|
311
322
|
requirements: []
|
@@ -320,5 +331,7 @@ test_files:
|
|
320
331
|
- spec/output_pool_spec.rb
|
321
332
|
- spec/query_spec.rb
|
322
333
|
- spec/spec_helper.rb
|
334
|
+
- spec/stats_spec.rb
|
335
|
+
- spec/target_spec.rb
|
323
336
|
- spec/typedef_manager_spec.rb
|
324
337
|
- spec/typedef_spec.rb
|