skylight-core 2.0.0.beta1

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.
Files changed (86) hide show
  1. checksums.yaml +7 -0
  2. data/lib/skylight/core/config.rb +454 -0
  3. data/lib/skylight/core/errors.rb +6 -0
  4. data/lib/skylight/core/fanout.rb +44 -0
  5. data/lib/skylight/core/formatters/http.rb +23 -0
  6. data/lib/skylight/core/gc.rb +107 -0
  7. data/lib/skylight/core/instrumentable.rb +144 -0
  8. data/lib/skylight/core/instrumenter.rb +249 -0
  9. data/lib/skylight/core/middleware.rb +101 -0
  10. data/lib/skylight/core/normalizers/action_controller/process_action.rb +50 -0
  11. data/lib/skylight/core/normalizers/action_controller/send_file.rb +50 -0
  12. data/lib/skylight/core/normalizers/action_view/render_collection.rb +22 -0
  13. data/lib/skylight/core/normalizers/action_view/render_partial.rb +21 -0
  14. data/lib/skylight/core/normalizers/action_view/render_template.rb +21 -0
  15. data/lib/skylight/core/normalizers/active_job/enqueue_at.rb +21 -0
  16. data/lib/skylight/core/normalizers/active_model_serializers/render.rb +26 -0
  17. data/lib/skylight/core/normalizers/active_record/instantiation.rb +17 -0
  18. data/lib/skylight/core/normalizers/active_record/sql.rb +33 -0
  19. data/lib/skylight/core/normalizers/active_support/cache.rb +20 -0
  20. data/lib/skylight/core/normalizers/active_support/cache_clear.rb +16 -0
  21. data/lib/skylight/core/normalizers/active_support/cache_decrement.rb +16 -0
  22. data/lib/skylight/core/normalizers/active_support/cache_delete.rb +16 -0
  23. data/lib/skylight/core/normalizers/active_support/cache_exist.rb +16 -0
  24. data/lib/skylight/core/normalizers/active_support/cache_fetch_hit.rb +16 -0
  25. data/lib/skylight/core/normalizers/active_support/cache_generate.rb +16 -0
  26. data/lib/skylight/core/normalizers/active_support/cache_increment.rb +16 -0
  27. data/lib/skylight/core/normalizers/active_support/cache_read.rb +16 -0
  28. data/lib/skylight/core/normalizers/active_support/cache_read_multi.rb +16 -0
  29. data/lib/skylight/core/normalizers/active_support/cache_write.rb +16 -0
  30. data/lib/skylight/core/normalizers/coach/handler_finish.rb +36 -0
  31. data/lib/skylight/core/normalizers/coach/middleware_finish.rb +23 -0
  32. data/lib/skylight/core/normalizers/couch_potato/query.rb +20 -0
  33. data/lib/skylight/core/normalizers/data_mapper/sql.rb +12 -0
  34. data/lib/skylight/core/normalizers/default.rb +27 -0
  35. data/lib/skylight/core/normalizers/elasticsearch/request.rb +20 -0
  36. data/lib/skylight/core/normalizers/faraday/request.rb +37 -0
  37. data/lib/skylight/core/normalizers/grape/endpoint.rb +30 -0
  38. data/lib/skylight/core/normalizers/grape/endpoint_render.rb +26 -0
  39. data/lib/skylight/core/normalizers/grape/endpoint_run.rb +33 -0
  40. data/lib/skylight/core/normalizers/grape/endpoint_run_filters.rb +23 -0
  41. data/lib/skylight/core/normalizers/moped/query.rb +100 -0
  42. data/lib/skylight/core/normalizers/sequel/sql.rb +12 -0
  43. data/lib/skylight/core/normalizers/sql.rb +49 -0
  44. data/lib/skylight/core/normalizers.rb +170 -0
  45. data/lib/skylight/core/probes/action_controller.rb +31 -0
  46. data/lib/skylight/core/probes/action_view.rb +37 -0
  47. data/lib/skylight/core/probes/active_model_serializers.rb +55 -0
  48. data/lib/skylight/core/probes/elasticsearch.rb +37 -0
  49. data/lib/skylight/core/probes/excon/middleware.rb +72 -0
  50. data/lib/skylight/core/probes/excon.rb +26 -0
  51. data/lib/skylight/core/probes/faraday.rb +22 -0
  52. data/lib/skylight/core/probes/grape.rb +80 -0
  53. data/lib/skylight/core/probes/httpclient.rb +46 -0
  54. data/lib/skylight/core/probes/middleware.rb +58 -0
  55. data/lib/skylight/core/probes/mongo.rb +171 -0
  56. data/lib/skylight/core/probes/mongoid.rb +21 -0
  57. data/lib/skylight/core/probes/moped.rb +39 -0
  58. data/lib/skylight/core/probes/net_http.rb +64 -0
  59. data/lib/skylight/core/probes/redis.rb +71 -0
  60. data/lib/skylight/core/probes/sequel.rb +33 -0
  61. data/lib/skylight/core/probes/sinatra.rb +69 -0
  62. data/lib/skylight/core/probes/tilt.rb +27 -0
  63. data/lib/skylight/core/probes.rb +129 -0
  64. data/lib/skylight/core/railtie.rb +166 -0
  65. data/lib/skylight/core/subscriber.rb +124 -0
  66. data/lib/skylight/core/test.rb +98 -0
  67. data/lib/skylight/core/trace.rb +190 -0
  68. data/lib/skylight/core/user_config.rb +61 -0
  69. data/lib/skylight/core/util/allocation_free.rb +26 -0
  70. data/lib/skylight/core/util/clock.rb +56 -0
  71. data/lib/skylight/core/util/deploy.rb +132 -0
  72. data/lib/skylight/core/util/gzip.rb +21 -0
  73. data/lib/skylight/core/util/inflector.rb +112 -0
  74. data/lib/skylight/core/util/logging.rb +127 -0
  75. data/lib/skylight/core/util/platform.rb +77 -0
  76. data/lib/skylight/core/util/proxy.rb +13 -0
  77. data/lib/skylight/core/util.rb +14 -0
  78. data/lib/skylight/core/vendor/active_support/notifications.rb +207 -0
  79. data/lib/skylight/core/vendor/active_support/per_thread_registry.rb +52 -0
  80. data/lib/skylight/core/vendor/thread_safe/non_concurrent_cache_backend.rb +133 -0
  81. data/lib/skylight/core/vendor/thread_safe/synchronized_cache_backend.rb +76 -0
  82. data/lib/skylight/core/vendor/thread_safe.rb +126 -0
  83. data/lib/skylight/core/version.rb +6 -0
  84. data/lib/skylight/core/vm/gc.rb +70 -0
  85. data/lib/skylight/core.rb +99 -0
  86. metadata +254 -0
@@ -0,0 +1,207 @@
1
+ require 'skylight/core/vendor/active_support/notifications/instrumenter'
2
+ require 'skylight/core/vendor/active_support/notifications/fanout'
3
+ require 'skylight/core/vendor/active_support/per_thread_registry'
4
+
5
+ module ActiveSupport
6
+ # = Notifications
7
+ #
8
+ # <tt>ActiveSupport::Notifications</tt> provides an instrumentation API for
9
+ # Ruby.
10
+ #
11
+ # == Instrumenters
12
+ #
13
+ # To instrument an event you just need to do:
14
+ #
15
+ # ActiveSupport::Notifications.instrument('render', extra: :information) do
16
+ # render text: 'Foo'
17
+ # end
18
+ #
19
+ # That executes the block first and notifies all subscribers once done.
20
+ #
21
+ # In the example above +render+ is the name of the event, and the rest is called
22
+ # the _payload_. The payload is a mechanism that allows instrumenters to pass
23
+ # extra information to subscribers. Payloads consist of a hash whose contents
24
+ # are arbitrary and generally depend on the event.
25
+ #
26
+ # == Subscribers
27
+ #
28
+ # You can consume those events and the information they provide by registering
29
+ # a subscriber.
30
+ #
31
+ # ActiveSupport::Notifications.subscribe('render') do |name, start, finish, id, payload|
32
+ # name # => String, name of the event (such as 'render' from above)
33
+ # start # => Time, when the instrumented block started execution
34
+ # finish # => Time, when the instrumented block ended execution
35
+ # id # => String, unique ID for this notification
36
+ # payload # => Hash, the payload
37
+ # end
38
+ #
39
+ # For instance, let's store all "render" events in an array:
40
+ #
41
+ # events = []
42
+ #
43
+ # ActiveSupport::Notifications.subscribe('render') do |*args|
44
+ # events << ActiveSupport::Notifications::Event.new(*args)
45
+ # end
46
+ #
47
+ # That code returns right away, you are just subscribing to "render" events.
48
+ # The block is saved and will be called whenever someone instruments "render":
49
+ #
50
+ # ActiveSupport::Notifications.instrument('render', extra: :information) do
51
+ # render text: 'Foo'
52
+ # end
53
+ #
54
+ # event = events.first
55
+ # event.name # => "render"
56
+ # event.duration # => 10 (in milliseconds)
57
+ # event.payload # => { extra: :information }
58
+ #
59
+ # The block in the <tt>subscribe</tt> call gets the name of the event, start
60
+ # timestamp, end timestamp, a string with a unique identifier for that event
61
+ # (something like "535801666f04d0298cd6"), and a hash with the payload, in
62
+ # that order.
63
+ #
64
+ # If an exception happens during that particular instrumentation the payload will
65
+ # have a key <tt>:exception</tt> with an array of two elements as value: a string with
66
+ # the name of the exception class, and the exception message.
67
+ #
68
+ # As the previous example depicts, the class <tt>ActiveSupport::Notifications::Event</tt>
69
+ # is able to take the arguments as they come and provide an object-oriented
70
+ # interface to that data.
71
+ #
72
+ # It is also possible to pass an object as the second parameter passed to the
73
+ # <tt>subscribe</tt> method instead of a block:
74
+ #
75
+ # module ActionController
76
+ # class PageRequest
77
+ # def call(name, started, finished, unique_id, payload)
78
+ # Rails.logger.debug ['notification:', name, started, finished, unique_id, payload].join(' ')
79
+ # end
80
+ # end
81
+ # end
82
+ #
83
+ # ActiveSupport::Notifications.subscribe('process_action.action_controller', ActionController::PageRequest.new)
84
+ #
85
+ # resulting in the following output within the logs including a hash with the payload:
86
+ #
87
+ # notification: process_action.action_controller 2012-04-13 01:08:35 +0300 2012-04-13 01:08:35 +0300 af358ed7fab884532ec7 {
88
+ # controller: "Devise::SessionsController",
89
+ # action: "new",
90
+ # params: {"action"=>"new", "controller"=>"devise/sessions"},
91
+ # format: :html,
92
+ # method: "GET",
93
+ # path: "/login/sign_in",
94
+ # status: 200,
95
+ # view_runtime: 279.3080806732178,
96
+ # db_runtime: 40.053
97
+ # }
98
+ #
99
+ # You can also subscribe to all events whose name matches a certain regexp:
100
+ #
101
+ # ActiveSupport::Notifications.subscribe(/render/) do |*args|
102
+ # ...
103
+ # end
104
+ #
105
+ # and even pass no argument to <tt>subscribe</tt>, in which case you are subscribing
106
+ # to all events.
107
+ #
108
+ # == Temporary Subscriptions
109
+ #
110
+ # Sometimes you do not want to subscribe to an event for the entire life of
111
+ # the application. There are two ways to unsubscribe.
112
+ #
113
+ # WARNING: The instrumentation framework is designed for long-running subscribers,
114
+ # use this feature sparingly because it wipes some internal caches and that has
115
+ # a negative impact on performance.
116
+ #
117
+ # === Subscribe While a Block Runs
118
+ #
119
+ # You can subscribe to some event temporarily while some block runs. For
120
+ # example, in
121
+ #
122
+ # callback = lambda {|*args| ... }
123
+ # ActiveSupport::Notifications.subscribed(callback, "sql.active_record") do
124
+ # ...
125
+ # end
126
+ #
127
+ # the callback will be called for all "sql.active_record" events instrumented
128
+ # during the execution of the block. The callback is unsubscribed automatically
129
+ # after that.
130
+ #
131
+ # === Manual Unsubscription
132
+ #
133
+ # The +subscribe+ method returns a subscriber object:
134
+ #
135
+ # subscriber = ActiveSupport::Notifications.subscribe("render") do |*args|
136
+ # ...
137
+ # end
138
+ #
139
+ # To prevent that block from being called anymore, just unsubscribe passing
140
+ # that reference:
141
+ #
142
+ # ActiveSupport::Notifications.unsubscribe(subscriber)
143
+ #
144
+ # == Default Queue
145
+ #
146
+ # Notifications ships with a queue implementation that consumes and publish events
147
+ # to log subscribers in a thread. You can use any queue implementation you want.
148
+ #
149
+ module Notifications
150
+ class << self
151
+ attr_accessor :notifier
152
+
153
+ def publish(name, *args)
154
+ notifier.publish(name, *args)
155
+ end
156
+
157
+ def instrument(name, payload = {})
158
+ if notifier.listening?(name)
159
+ instrumenter.instrument(name, payload) { yield payload if block_given? }
160
+ else
161
+ yield payload if block_given?
162
+ end
163
+ end
164
+
165
+ def subscribe(*args, &block)
166
+ notifier.subscribe(*args, &block)
167
+ end
168
+
169
+ def subscribed(callback, *args, &block)
170
+ subscriber = subscribe(*args, &callback)
171
+ yield
172
+ ensure
173
+ unsubscribe(subscriber)
174
+ end
175
+
176
+ def unsubscribe(args)
177
+ notifier.unsubscribe(args)
178
+ end
179
+
180
+ def instrumenter
181
+ InstrumentationRegistry.instrumenter_for(notifier)
182
+ end
183
+ end
184
+
185
+ # This class is a registry which holds all of the +Instrumenter+ objects
186
+ # in a particular thread local. To access the +Instrumenter+ object for a
187
+ # particular +notifier+, you can call the following method:
188
+ #
189
+ # InstrumentationRegistry.instrumenter_for(notifier)
190
+ #
191
+ # The instrumenters for multiple notifiers are held in a single instance of
192
+ # this class.
193
+ class InstrumentationRegistry # :nodoc:
194
+ extend ActiveSupport::PerThreadRegistry
195
+
196
+ def initialize
197
+ @registry = {}
198
+ end
199
+
200
+ def instrumenter_for(notifier)
201
+ @registry[notifier] ||= Instrumenter.new(notifier)
202
+ end
203
+ end
204
+
205
+ self.notifier = Fanout.new
206
+ end
207
+ end
@@ -0,0 +1,52 @@
1
+ module ActiveSupport
2
+ # This module is used to encapsulate access to thread local variables.
3
+ #
4
+ # Instead of polluting the thread locals namespace:
5
+ #
6
+ # Thread.current[:connection_handler]
7
+ #
8
+ # you define a class that extends this module:
9
+ #
10
+ # module ActiveRecord
11
+ # class RuntimeRegistry
12
+ # extend ActiveSupport::PerThreadRegistry
13
+ #
14
+ # attr_accessor :connection_handler
15
+ # end
16
+ # end
17
+ #
18
+ # and invoke the declared instance accessors as class methods. So
19
+ #
20
+ # ActiveRecord::RuntimeRegistry.connection_handler = connection_handler
21
+ #
22
+ # sets a connection handler local to the current thread, and
23
+ #
24
+ # ActiveRecord::RuntimeRegistry.connection_handler
25
+ #
26
+ # returns a connection handler local to the current thread.
27
+ #
28
+ # This feature is accomplished by instantiating the class and storing the
29
+ # instance as a thread local keyed by the class name. In the example above
30
+ # a key "ActiveRecord::RuntimeRegistry" is stored in <tt>Thread.current</tt>.
31
+ # The class methods proxy to said thread local instance.
32
+ #
33
+ # If the class has an initializer, it must accept no arguments.
34
+ module PerThreadRegistry
35
+ protected
36
+
37
+ def method_missing(name, *args, &block) # :nodoc:
38
+ # Caches the method definition as a singleton method of the receiver.
39
+ define_singleton_method(name) do |*a, &b|
40
+ per_thread_registry_instance.public_send(name, *a, &b)
41
+ end
42
+
43
+ send(name, *args, &block)
44
+ end
45
+
46
+ private
47
+
48
+ def per_thread_registry_instance
49
+ Thread.current[name] ||= new
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,133 @@
1
+ module ThreadSafe
2
+ class NonConcurrentCacheBackend
3
+ # WARNING: all public methods of the class must operate on the @backend directly without calling each other. This is important
4
+ # because of the SynchronizedCacheBackend which uses a non-reentrant mutex for perfomance reasons.
5
+ def initialize(options = nil)
6
+ @backend = {}
7
+ end
8
+
9
+ def [](key)
10
+ @backend[key]
11
+ end
12
+
13
+ def []=(key, value)
14
+ @backend[key] = value
15
+ end
16
+
17
+ def compute_if_absent(key)
18
+ if NULL != (stored_value = @backend.fetch(key, NULL))
19
+ stored_value
20
+ else
21
+ @backend[key] = yield
22
+ end
23
+ end
24
+
25
+ def replace_pair(key, old_value, new_value)
26
+ if pair?(key, old_value)
27
+ @backend[key] = new_value
28
+ true
29
+ else
30
+ false
31
+ end
32
+ end
33
+
34
+ def replace_if_exists(key, new_value)
35
+ if NULL != (stored_value = @backend.fetch(key, NULL))
36
+ @backend[key] = new_value
37
+ stored_value
38
+ end
39
+ end
40
+
41
+ def compute_if_present(key)
42
+ if NULL != (stored_value = @backend.fetch(key, NULL))
43
+ store_computed_value(key, yield(stored_value))
44
+ end
45
+ end
46
+
47
+ def compute(key)
48
+ store_computed_value(key, yield(@backend[key]))
49
+ end
50
+
51
+ def merge_pair(key, value)
52
+ if NULL == (stored_value = @backend.fetch(key, NULL))
53
+ @backend[key] = value
54
+ else
55
+ store_computed_value(key, yield(stored_value))
56
+ end
57
+ end
58
+
59
+ def get_and_set(key, value)
60
+ stored_value = @backend[key]
61
+ @backend[key] = value
62
+ stored_value
63
+ end
64
+
65
+ def key?(key)
66
+ @backend.key?(key)
67
+ end
68
+
69
+ def value?(value)
70
+ @backend.value?(value)
71
+ end
72
+
73
+ def delete(key)
74
+ @backend.delete(key)
75
+ end
76
+
77
+ def delete_pair(key, value)
78
+ if pair?(key, value)
79
+ @backend.delete(key)
80
+ true
81
+ else
82
+ false
83
+ end
84
+ end
85
+
86
+ def clear
87
+ @backend.clear
88
+ self
89
+ end
90
+
91
+ def each_pair
92
+ dupped_backend.each_pair do |k, v|
93
+ yield k, v
94
+ end
95
+ self
96
+ end
97
+
98
+ def size
99
+ @backend.size
100
+ end
101
+
102
+ def get_or_default(key, default_value)
103
+ @backend.fetch(key, default_value)
104
+ end
105
+
106
+ alias_method :_get, :[]
107
+ alias_method :_set, :[]=
108
+ private :_get, :_set
109
+ private
110
+ def initialize_copy(other)
111
+ super
112
+ @backend = {}
113
+ self
114
+ end
115
+
116
+ def dupped_backend
117
+ @backend.dup
118
+ end
119
+
120
+ def pair?(key, expected_value)
121
+ NULL != (stored_value = @backend.fetch(key, NULL)) && expected_value.equal?(stored_value)
122
+ end
123
+
124
+ def store_computed_value(key, new_value)
125
+ if new_value.nil?
126
+ @backend.delete(key)
127
+ nil
128
+ else
129
+ @backend[key] = new_value
130
+ end
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,76 @@
1
+ module ThreadSafe
2
+ class SynchronizedCacheBackend < NonConcurrentCacheBackend
3
+ require 'mutex_m'
4
+ include Mutex_m
5
+ # WARNING: Mutex_m is a non-reentrant lock, so the synchronized methods are not allowed to call each other.
6
+
7
+ def [](key)
8
+ synchronize { super }
9
+ end
10
+
11
+ def []=(key, value)
12
+ synchronize { super }
13
+ end
14
+
15
+ def compute_if_absent(key)
16
+ synchronize { super }
17
+ end
18
+
19
+ def compute_if_present(key)
20
+ synchronize { super }
21
+ end
22
+
23
+ def compute(key)
24
+ synchronize { super }
25
+ end
26
+
27
+ def merge_pair(key, value)
28
+ synchronize { super }
29
+ end
30
+
31
+ def replace_pair(key, old_value, new_value)
32
+ synchronize { super }
33
+ end
34
+
35
+ def replace_if_exists(key, new_value)
36
+ synchronize { super }
37
+ end
38
+
39
+ def get_and_set(key, value)
40
+ synchronize { super }
41
+ end
42
+
43
+ def key?(key)
44
+ synchronize { super }
45
+ end
46
+
47
+ def value?(value)
48
+ synchronize { super }
49
+ end
50
+
51
+ def delete(key)
52
+ synchronize { super }
53
+ end
54
+
55
+ def delete_pair(key, value)
56
+ synchronize { super }
57
+ end
58
+
59
+ def clear
60
+ synchronize { super }
61
+ end
62
+
63
+ def size
64
+ synchronize { super }
65
+ end
66
+
67
+ def get_or_default(key, default_value)
68
+ synchronize { super }
69
+ end
70
+
71
+ private
72
+ def dupped_backend
73
+ synchronize { super }
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,126 @@
1
+ require 'thread'
2
+
3
+ module ThreadSafe
4
+ autoload :NonConcurrentCacheBackend, 'skylight/core/vendor/thread_safe/non_concurrent_cache_backend'
5
+ autoload :SynchronizedCacheBackend, 'skylight/core/vendor/thread_safe/synchronized_cache_backend'
6
+
7
+ ConcurrentCacheBackend = SynchronizedCacheBackend
8
+
9
+ class Cache < ConcurrentCacheBackend
10
+ KEY_ERROR = defined?(KeyError) ? KeyError : IndexError # there is no KeyError in 1.8 mode
11
+
12
+ def initialize(options = nil, &block)
13
+ if options.kind_of?(::Hash)
14
+ validate_options_hash!(options)
15
+ else
16
+ options = nil
17
+ end
18
+
19
+ super(options)
20
+ @default_proc = block
21
+ end
22
+
23
+ def [](key)
24
+ if value = super
25
+ value
26
+ elsif @default_proc && !key?(key)
27
+ @default_proc.call(self, key)
28
+ else
29
+ value
30
+ end
31
+ end
32
+
33
+ def fetch(key, default_value = NULL)
34
+ if NULL != (value = get_or_default(key, NULL))
35
+ value
36
+ elsif block_given?
37
+ yield key
38
+ elsif NULL != default_value
39
+ default_value
40
+ else
41
+ raise KEY_ERROR, 'key not found'
42
+ end
43
+ end
44
+
45
+ def put_if_absent(key, value)
46
+ computed = false
47
+ result = compute_if_absent(key) do
48
+ computed = true
49
+ value
50
+ end
51
+ computed ? nil : result
52
+ end unless method_defined?(:put_if_absent)
53
+
54
+ def value?(value)
55
+ each_value do |v|
56
+ return true if value.equal?(v)
57
+ end
58
+ false
59
+ end unless method_defined?(:value?)
60
+
61
+ def keys
62
+ arr = []
63
+ each_pair {|k, v| arr << k}
64
+ arr
65
+ end unless method_defined?(:keys)
66
+
67
+ def values
68
+ arr = []
69
+ each_pair {|k, v| arr << v}
70
+ arr
71
+ end unless method_defined?(:values)
72
+
73
+ def each_key
74
+ each_pair {|k, v| yield k}
75
+ end unless method_defined?(:each_key)
76
+
77
+ def each_value
78
+ each_pair {|k, v| yield v}
79
+ end unless method_defined?(:each_value)
80
+
81
+ def empty?
82
+ each_pair {|k, v| return false}
83
+ true
84
+ end unless method_defined?(:empty?)
85
+
86
+ def size
87
+ count = 0
88
+ each_pair {|k, v| count += 1}
89
+ count
90
+ end unless method_defined?(:size)
91
+
92
+ def marshal_dump
93
+ raise TypeError, "can't dump hash with default proc" if @default_proc
94
+ h = {}
95
+ each_pair {|k, v| h[k] = v}
96
+ h
97
+ end
98
+
99
+ def marshal_load(hash)
100
+ initialize
101
+ populate_from(hash)
102
+ end
103
+
104
+ undef :freeze
105
+
106
+ private
107
+ def initialize_copy(other)
108
+ super
109
+ populate_from(other)
110
+ end
111
+
112
+ def populate_from(hash)
113
+ hash.each_pair {|k, v| self[k] = v}
114
+ self
115
+ end
116
+
117
+ def validate_options_hash!(options)
118
+ if (initial_capacity = options[:initial_capacity]) && (!initial_capacity.kind_of?(Fixnum) || initial_capacity < 0)
119
+ raise ArgumentError, ":initial_capacity must be a positive Fixnum"
120
+ end
121
+ if (load_factor = options[:load_factor]) && (!load_factor.kind_of?(Numeric) || load_factor <= 0 || load_factor > 1)
122
+ raise ArgumentError, ":load_factor must be a number between 0 and 1"
123
+ end
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,6 @@
1
+ module Skylight
2
+ module Core
3
+ VERSION = '2.0.0-beta1'
4
+ end
5
+ end
6
+
@@ -0,0 +1,70 @@
1
+
2
+ module Skylight::Core
3
+ # @api private
4
+ module VM
5
+ if defined?(JRUBY_VERSION)
6
+
7
+ # This doesn't quite work as we would like it. I believe that the GC
8
+ # statistics includes time that is not stop-the-world, this does not
9
+ # necessarily take time away from the application.
10
+ #
11
+ # require 'java'
12
+ # class GC
13
+ # def initialize
14
+ # @factory = Java::JavaLangManagement::ManagementFactory
15
+ # end
16
+ #
17
+ # def enable
18
+ # end
19
+ #
20
+ # def total_time
21
+ # res = 0.0
22
+ #
23
+ # @factory.garbage_collector_mx_beans.each do |mx|
24
+ # res += (mx.collection_time.to_f / 1_000.0)
25
+ # end
26
+ #
27
+ # res
28
+ # end
29
+ # end
30
+
31
+ elsif defined?(::GC::Profiler)
32
+
33
+ class GC
34
+ def initialize
35
+ @total = 0
36
+ end
37
+
38
+ def enable
39
+ ::GC::Profiler.enable
40
+ end
41
+
42
+ def total_time
43
+ # Reported in seconds
44
+ run = (::GC::Profiler.total_time * 1_000_000).to_i
45
+
46
+ if run > 0
47
+ ::GC::Profiler.clear
48
+ end
49
+
50
+ @total += run
51
+ end
52
+ end
53
+
54
+ end
55
+
56
+ # Fallback
57
+ unless defined?(VM::GC)
58
+
59
+ class GC
60
+ def enable
61
+ end
62
+
63
+ def total_time
64
+ 0
65
+ end
66
+ end
67
+
68
+ end
69
+ end
70
+ end