andromeda 0.1 → 0.1.2

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.
@@ -0,0 +1,48 @@
1
+ module Andromeda
2
+
3
+ module Impl
4
+
5
+ module To_S
6
+
7
+ def to_s(short = false)
8
+ if short
9
+ to_short_s
10
+ else
11
+ super_str = super()
12
+ class_name = self.class.name.split('::')[-1]
13
+ obj_id = object_id.to_s(16)
14
+ "\#<#{class_name}:0x#{obj_id}#{to_s(true)}>"
15
+ end
16
+ end
17
+
18
+ def to_short_s ; '' end
19
+
20
+ def self.short_s(v = value)
21
+ return ":#{v}" if v.is_a?(Symbol)
22
+ return "'#{v}'" if v.is_a?(String)
23
+ return 'nil' unless v
24
+ "#{v}"
25
+ end
26
+
27
+ end
28
+
29
+ # Shared base class of Spot and Impl::PrePlan
30
+ class ConnectorBase
31
+ # @return [Spot] entry.intern nil
32
+ def start ; entry.intern(nil) end
33
+
34
+ # post_to nil, data, tags_in
35
+ #
36
+ # @return [self]
37
+ def post(data, tags_in = {}) ; post_to nil, data, tags_in end
38
+
39
+ alias_method :<<, :post
40
+
41
+ # post_to LocalTrack.instance, data, tags_in
42
+ #
43
+ # @return [self]
44
+ def post_local(data, tags_in = {}) ; post_to Guides::LocalTrack.instance, data, tags_in end
45
+ end
46
+
47
+ end
48
+ end
@@ -0,0 +1,89 @@
1
+ module Andromeda
2
+
3
+ module Impl
4
+
5
+ # Generator for random xorable ids (used for markers)
6
+ class XorId
7
+ include To_S
8
+
9
+ protected
10
+
11
+ def initialize(len, random = true, init_data = nil)
12
+ raise ArgumentError unless len.kind_of?(Fixnum)
13
+ raise ArgumentError unless len >= 0
14
+
15
+ @data = if init_data
16
+ init_data
17
+ else
18
+ if random
19
+ then len.times.map { Id.rnd_byte }
20
+ else len.times.map { 0 } end
21
+ end
22
+ end
23
+
24
+ public
25
+
26
+ def clone_to_copy? ; false end
27
+ def identical_copy ; self end
28
+
29
+ def length ; @data.length end
30
+ def zero? ; each { |b| return false unless b == 0 } ; true end
31
+
32
+ def [](key) ; @data[key] end
33
+
34
+ def same_length?(obj) ; self.length == obj.length end
35
+
36
+ def each ; this = self ; 0.upto(length-1).each { |i| yield this[i] } end
37
+ def each_with_index ; this = self ; 0.upto(length-1).each { |i| yield i, this[i] } end
38
+
39
+ # Compare self to b
40
+ # @param [Id] b
41
+ def ==(b)
42
+ return true if self.equal? b
43
+ return false if b.nil?
44
+ return false unless b.class.equal? self.class
45
+ return false unless same_length? b
46
+ zip_bytes(b) { |i, j| return false if i != j }
47
+ true
48
+ end
49
+
50
+ def hash ; @data.hash end
51
+
52
+ # xor self and b's ids component-wise
53
+ # @param [Array<Fixnum>] b
54
+ # @return [Id]
55
+ def xor(b)
56
+ r = []
57
+ zip_bytes(b) { |i,j| r << (i ^ j) }
58
+ Id.new r.length, false, r
59
+ end
60
+
61
+ def to_short_s
62
+ r = ''
63
+ each { |b| r << Id.two_char_hex_str(b.to_s(16)) }
64
+ r
65
+ end
66
+
67
+ def inspect ; to_s end
68
+
69
+ private
70
+
71
+ def zip_bytes(b)
72
+ a = self
73
+ 0.upto(length-1).each { |i| yield a[i], b[i] }
74
+ end
75
+
76
+ def self.rnd_byte ; Random.rand(256) end
77
+
78
+ def self.two_char_hex_str(s)
79
+ case s.length
80
+ when 0 then '00'
81
+ when 1 then "0#{s}"
82
+ else s
83
+ end
84
+ end
85
+ end
86
+
87
+ end
88
+
89
+ end
@@ -0,0 +1,172 @@
1
+ module Andromeda
2
+
3
+ module Kit
4
+
5
+ module Transf
6
+ attr_accessor :filter
7
+ attr_accessor :mapper
8
+
9
+ def deliver_data(name, meth, key, val, tags_in)
10
+ if signal_name?(name)
11
+ super name, meth, key, val, tags_in
12
+ else
13
+ filter_ = filter
14
+ mapper_ = mapper
15
+ if !(filter_ && filter_.call(val))
16
+ super name, meth, key, (if mapper_ then mapper_.call(val) else val end), tags_in
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ class Tee < Plan
23
+ attr_accessor :level
24
+ attr_accessor :other
25
+ attr_accessor :delay
26
+
27
+ def initialize(config = {})
28
+ config = { nick: config } unless config.is_a? Hash || config.is_a?(Spot)
29
+ config = { other: config } unless config.is_a? Hash
30
+ super config
31
+
32
+ @level ||= :info
33
+ end
34
+
35
+ def initialize_copy(other)
36
+ @level = other.level.identical_copy
37
+ @delay = other.delay.identical_copy
38
+ end
39
+
40
+ def on_enter(key, val)
41
+ log_ = log
42
+ level_ = level
43
+ sleep delay.to_i if delay
44
+ if log_ && level_
45
+ cur_name = current_name
46
+ key_str = Andromeda::Impl::To_S.short_s key
47
+ val_str = Andromeda::Impl::To_S.short_s val
48
+ log_str = "#{to_s}.#{cur_name}(#{key_str}, #{val_str})"
49
+ tags.each_pair { |k, v| log_str << " #{k}=#{Andromeda::Impl::To_S.short_s(v)}" }
50
+ log_str << " tid=0x#{Thread.current.object_id.to_s(16)}"
51
+ log_.send level, log_str
52
+ end
53
+ other_ = other
54
+ other_ << val if other_
55
+ super key, val
56
+ end
57
+ end
58
+
59
+ class Targeting < Plan
60
+ attr_accessor :targets
61
+
62
+ def initialize(config = {})
63
+ super config
64
+ @targets ||= {}
65
+ end
66
+
67
+ def target_values ; t = targets ; t.values rescue t end
68
+ end
69
+
70
+ class Broadc < Targeting
71
+ def on_enter(key, val)
72
+ target_values { |t| intern(t) << val rescue nil }
73
+ end
74
+ end
75
+
76
+ class Switch < Targeting
77
+ def on_enter(key, val)
78
+ (intern(key) rescue exit) << val rescue nil
79
+ end
80
+ end
81
+
82
+ class SinglePlan < Plan
83
+ def init_guide ; Guides::SinglePoolGuide.new end
84
+ end
85
+
86
+ class InlineKeyRouter < SinglePlan
87
+ def key_spot(name, key) ; key end
88
+ end
89
+
90
+ class Gatherer < SinglePlan
91
+ include Transf
92
+ end
93
+
94
+ class Reducer < Gatherer
95
+ attr_accessor :state
96
+ attr_accessor :reducer
97
+
98
+ attr_spot :new_state
99
+
100
+ def on_enter(key, val)
101
+ reducer_ = reducer
102
+
103
+ state_ = state
104
+ new_ = reducer_.call state_, key, val
105
+ unless new_ == state_
106
+ state = new_
107
+ new_state << state if new_state
108
+ end
109
+ end
110
+ end
111
+
112
+ class FileReader < Plan
113
+ attr_reader :path
114
+ attr_reader :mode
115
+
116
+ def initialize(config = {})
117
+ super config
118
+ @mode ||= init_mode
119
+ end
120
+
121
+ def data_tag(name, key, val, tags_in)
122
+ tags_out = super
123
+ tags_out[:first] = val.first rescue 0
124
+ tags_out[:last] = val.last rescue -1
125
+ tags_out
126
+ end
127
+
128
+ def init_mode ; 'r' end
129
+
130
+ protected
131
+
132
+ def on_enter(key, val)
133
+ file = File.open path, mode
134
+ begin
135
+ file.seek tags[:first]
136
+ tags[:last] = file.size - 1 if tags[:last] < 0
137
+ tags[:num] = tags[:last] - tags[:first]
138
+ if block_given? then yield file else super key, val end
139
+ ensure
140
+ file.close
141
+ end
142
+ end
143
+
144
+ end
145
+
146
+ class FileChunker < FileReader
147
+ attr_reader :num_chunks
148
+
149
+ def initialize(config = {})
150
+ super config
151
+ @num_chunks ||= Guides::PoolGuide.num_procs
152
+ end
153
+
154
+ def on_enter(key, val)
155
+ num_c = num_chunks
156
+ super key, val do |f|
157
+ fst = tags[:first]
158
+ lst = tags[:last]
159
+ sz = tags[:num] / num_c rescue 1
160
+ sz = 1 if sz < 0
161
+ while fst <= lst
162
+ nxt = fst + sz
163
+ nxt = lst if nxt > lst
164
+ exit << Range.new(fst, nxt)
165
+ fst = nxt + 1
166
+ end
167
+ end
168
+ end
169
+ end
170
+
171
+ end
172
+ end
@@ -0,0 +1,3 @@
1
+ module Andromeda
2
+ # unimplemented
3
+ end
@@ -0,0 +1,130 @@
1
+ module Andromeda
2
+
3
+ class Plan < Impl::ProtoPlan
4
+
5
+ meth_spot :enter
6
+ attr_spot :errors
7
+
8
+ signal_spot :errors
9
+
10
+ attr_accessor :log
11
+ attr_accessor :marker
12
+ attr_accessor :nick
13
+
14
+ attr_accessor :error_level
15
+
16
+ attr_accessor :trace_enter
17
+ attr_accessor :trace_exit
18
+
19
+
20
+ def initialize(config = {})
21
+ super config
22
+ @trace_enter ||= init_trace_hash :enter
23
+ @trace_exit ||= init_trace_hash :emit
24
+ @error_level ||= :error
25
+ end
26
+
27
+ def initialize_copy(other)
28
+ super other
29
+ @trace_enter = other.trace_enter.identical_copy
30
+ @trace_exit = other.trace_exit.identical_copy
31
+ @error_level = other.error_level.identical_copy
32
+ @nick = other.nick.identical_copy
33
+ end
34
+
35
+ def tap ; yield self end
36
+
37
+ def log ; @log = DefaultLogger.instance end
38
+ def mark ; @mark = Id.zero unless @mark ; @mark end
39
+
40
+ def on_enter(k, v)
41
+ exit_ = exit
42
+ exit_ << v if exit_
43
+ end
44
+
45
+ def to_short_s
46
+ super_ = super()
47
+ nick_ = nick
48
+ if nick_
49
+ then "#{super_} aka: #{Impl::To_S.short_s(nick_)}"
50
+ else super_ end
51
+ end
52
+
53
+ protected
54
+
55
+ def transport_data name, track, meth, key, val, tags_in
56
+ scope = tags_in[:scope]
57
+ enter_level = trace_level trace_enter, name
58
+ exit_level = trace_level trace_exit, name
59
+ details = { name: name, plan: self, track: track, key: key, val: val }
60
+ track.follow(scope) do
61
+ begin
62
+ trace :enter, enter_level, name, details if enter_level
63
+ deliver_data name, meth, key, val, tags_in
64
+ trace :exit, exit_level, name, details if exit_level
65
+ rescue Exception => e
66
+ uncaught_exception name, key, val, e
67
+ end
68
+ end
69
+ end
70
+
71
+ def init_trace_hash(kind) ; {} end
72
+
73
+ def trace_level(h, name) ; if h.is_a?(Symbol) then h else (h[name] rescue nil) end end
74
+
75
+ def trace(kind, level, name, details)
76
+ log.send level, InfoMsg.str("TRACE :#{kind} :#{name}", details) if log
77
+ end
78
+
79
+ def deliver_data(name, meth, k, v, tags_in)
80
+ update_mark
81
+ tags.update tags_in
82
+ meth.call k, v
83
+ end
84
+
85
+ def signal_error(e)
86
+ errors_ = errors
87
+ errors_ << e if errors_
88
+ end
89
+
90
+ def signal_uncaught(e)
91
+ log.send error_level, e rescue nil
92
+ signal_error e
93
+ end
94
+
95
+ def reset_mark(new_mark)
96
+ tags[:mark] = if new_mark then new_mark else Id.zero end
97
+ end
98
+
99
+ def mark ; tags[:mark] end
100
+
101
+ def check_mark
102
+ mark_ = mark
103
+ raise RuntimeError, 'Invalid mark' if mark_ && !mark_.zero?
104
+ end
105
+
106
+ def update_mark
107
+ marker_ = marker
108
+ if marker_ && !marker_.zero?
109
+ mark_ = mark
110
+ if mark_
111
+ then reset_mark mark_.xor(marker_)
112
+ else reset_mark mark_ end
113
+ end
114
+ end
115
+
116
+ def uncaught_exception(name, key, value, e)
117
+ begin
118
+ details = { name: name, key: key, val: value, cause: e }
119
+ info = InfoMsg.str 'Uncaught exception', details
120
+ err = ExecError.new(info)
121
+ err.set_backtrace e.backtrace
122
+ signal_uncaught e
123
+ rescue Exception => e2
124
+ details[:cause] = e2
125
+ log.error InfoMsg.str('Failure handling uncaught exception', details) rescue nil
126
+ end
127
+ end
128
+ end
129
+
130
+ end
@@ -0,0 +1,70 @@
1
+ module Andromeda
2
+
3
+ module Guides
4
+
5
+ class PoolGuide < Guide
6
+ attr_reader :max_procs
7
+ attr_reader :pool_track
8
+
9
+ # @return [Fixnum] number of processors as determined by Facter
10
+ def self.num_procs
11
+ @num_procs = Facter.sp_number_processors.strip.to_i unless defined?(@num_procs)
12
+ @num_procs
13
+ end
14
+
15
+ def initialize(num_procs = nil)
16
+ num_procs = PoolGuide.num_procs unless num_procs
17
+ raise ArgumentError unless num_procs.is_a?(Fixnum)
18
+ raise ArgumentError unless num_procs > 0
19
+ @max_procs = num_procs
20
+ @pool_track = PoolTrack.new ThreadPool.new(@max_procs)
21
+ end
22
+
23
+ def track(spot, label, suggested_track = nil)
24
+ return suggested_track if suggested_track
25
+ return @pool_track
26
+ end
27
+
28
+ def pack(plan, track, was_suggested = false)
29
+ return plan if plan.frozen?
30
+ return plan.identical_copy if was_suggested
31
+ if max_procs > 1 then plan.identical_copy else plan end
32
+ end
33
+ end
34
+
35
+ class PoolTrack
36
+ include DispatchingTrack
37
+
38
+ attr_reader :pool
39
+
40
+ def initialize(pool)
41
+ @pool = pool
42
+ end
43
+
44
+ protected
45
+
46
+ def process(&thunk)
47
+ # DefaultLogger.instance.info ":enter #{pool.inspect}"
48
+ pool.process &thunk
49
+ # DefaultLogger.instance.info ":exit #{pool.inspect}"
50
+ end
51
+ end
52
+
53
+ class SharedPoolGuide < PoolGuide
54
+ include Singleton
55
+
56
+ def initialize
57
+ super PoolGuide.num_procs
58
+ end
59
+ end
60
+
61
+ class SinglePoolGuide < PoolGuide
62
+ def initialize ; super 1 end
63
+ end
64
+
65
+ class SharedSinglePoolGuide < SinglePoolGuide
66
+ include Singleton
67
+ end
68
+
69
+ end
70
+ end