garcun 0.0.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.
Files changed (139) hide show
  1. checksums.yaml +7 -0
  2. data/.gitattributes +17 -0
  3. data/.gitignore +197 -0
  4. data/.rspec +2 -0
  5. data/Gemfile +22 -0
  6. data/LICENSE +201 -0
  7. data/README.md +521 -0
  8. data/Rakefile +47 -0
  9. data/garcun.gemspec +83 -0
  10. data/lib/garcon.rb +290 -0
  11. data/lib/garcon/chef/chef_helpers.rb +343 -0
  12. data/lib/garcon/chef/coerce/coercer.rb +134 -0
  13. data/lib/garcon/chef/coerce/coercions/boolean_definitions.rb +34 -0
  14. data/lib/garcon/chef/coerce/coercions/date_definitions.rb +32 -0
  15. data/lib/garcon/chef/coerce/coercions/date_time_definitions.rb +32 -0
  16. data/lib/garcon/chef/coerce/coercions/fixnum_definitions.rb +34 -0
  17. data/lib/garcon/chef/coerce/coercions/float_definitions.rb +32 -0
  18. data/lib/garcon/chef/coerce/coercions/hash_definitions.rb +29 -0
  19. data/lib/garcon/chef/coerce/coercions/integer_definitions.rb +31 -0
  20. data/lib/garcon/chef/coerce/coercions/string_definitions.rb +45 -0
  21. data/lib/garcon/chef/coerce/coercions/time_definitions.rb +32 -0
  22. data/lib/garcon/chef/handler/devreporter.rb +127 -0
  23. data/lib/garcon/chef/log.rb +64 -0
  24. data/lib/garcon/chef/node.rb +100 -0
  25. data/lib/garcon/chef/provider/civilize.rb +209 -0
  26. data/lib/garcon/chef/provider/development.rb +159 -0
  27. data/lib/garcon/chef/provider/download.rb +420 -0
  28. data/lib/garcon/chef/provider/house_keeping.rb +265 -0
  29. data/lib/garcon/chef/provider/node_cache.rb +31 -0
  30. data/lib/garcon/chef/provider/partial.rb +183 -0
  31. data/lib/garcon/chef/provider/recovery.rb +80 -0
  32. data/lib/garcon/chef/provider/zip_file.rb +271 -0
  33. data/lib/garcon/chef/resource/attribute.rb +52 -0
  34. data/lib/garcon/chef/resource/base_dsl.rb +174 -0
  35. data/lib/garcon/chef/resource/blender.rb +140 -0
  36. data/lib/garcon/chef/resource/lazy_eval.rb +66 -0
  37. data/lib/garcon/chef/resource/resource_name.rb +109 -0
  38. data/lib/garcon/chef/secret_bag.rb +204 -0
  39. data/lib/garcon/chef/validations.rb +76 -0
  40. data/lib/garcon/chef_inclusions.rb +151 -0
  41. data/lib/garcon/configuration.rb +138 -0
  42. data/lib/garcon/core_ext.rb +39 -0
  43. data/lib/garcon/core_ext/array.rb +27 -0
  44. data/lib/garcon/core_ext/binding.rb +64 -0
  45. data/lib/garcon/core_ext/boolean.rb +66 -0
  46. data/lib/garcon/core_ext/duration.rb +271 -0
  47. data/lib/garcon/core_ext/enumerable.rb +34 -0
  48. data/lib/garcon/core_ext/file.rb +127 -0
  49. data/lib/garcon/core_ext/filetest.rb +62 -0
  50. data/lib/garcon/core_ext/hash.rb +279 -0
  51. data/lib/garcon/core_ext/kernel.rb +159 -0
  52. data/lib/garcon/core_ext/lazy.rb +222 -0
  53. data/lib/garcon/core_ext/method_access.rb +243 -0
  54. data/lib/garcon/core_ext/module.rb +92 -0
  55. data/lib/garcon/core_ext/nil.rb +53 -0
  56. data/lib/garcon/core_ext/numeric.rb +44 -0
  57. data/lib/garcon/core_ext/object.rb +342 -0
  58. data/lib/garcon/core_ext/pathname.rb +152 -0
  59. data/lib/garcon/core_ext/process.rb +41 -0
  60. data/lib/garcon/core_ext/random.rb +497 -0
  61. data/lib/garcon/core_ext/string.rb +312 -0
  62. data/lib/garcon/core_ext/struct.rb +49 -0
  63. data/lib/garcon/core_ext/symbol.rb +170 -0
  64. data/lib/garcon/core_ext/time.rb +234 -0
  65. data/lib/garcon/exceptions.rb +101 -0
  66. data/lib/garcon/inflections.rb +237 -0
  67. data/lib/garcon/inflections/defaults.rb +79 -0
  68. data/lib/garcon/inflections/inflections.rb +182 -0
  69. data/lib/garcon/inflections/rules_collection.rb +37 -0
  70. data/lib/garcon/secret.rb +271 -0
  71. data/lib/garcon/stash/format.rb +114 -0
  72. data/lib/garcon/stash/journal.rb +226 -0
  73. data/lib/garcon/stash/queue.rb +83 -0
  74. data/lib/garcon/stash/serializer.rb +86 -0
  75. data/lib/garcon/stash/store.rb +435 -0
  76. data/lib/garcon/task.rb +31 -0
  77. data/lib/garcon/task/atomic.rb +151 -0
  78. data/lib/garcon/task/atomic_boolean.rb +127 -0
  79. data/lib/garcon/task/condition.rb +99 -0
  80. data/lib/garcon/task/copy_on_notify_observer_set.rb +154 -0
  81. data/lib/garcon/task/copy_on_write_observer_set.rb +153 -0
  82. data/lib/garcon/task/count_down_latch.rb +92 -0
  83. data/lib/garcon/task/delay.rb +196 -0
  84. data/lib/garcon/task/dereferenceable.rb +144 -0
  85. data/lib/garcon/task/event.rb +119 -0
  86. data/lib/garcon/task/executor.rb +275 -0
  87. data/lib/garcon/task/executor_options.rb +59 -0
  88. data/lib/garcon/task/future.rb +107 -0
  89. data/lib/garcon/task/immediate_executor.rb +84 -0
  90. data/lib/garcon/task/ivar.rb +171 -0
  91. data/lib/garcon/task/lazy_reference.rb +74 -0
  92. data/lib/garcon/task/monotonic_time.rb +69 -0
  93. data/lib/garcon/task/obligation.rb +256 -0
  94. data/lib/garcon/task/observable.rb +101 -0
  95. data/lib/garcon/task/priority_queue.rb +234 -0
  96. data/lib/garcon/task/processor_count.rb +128 -0
  97. data/lib/garcon/task/read_write_lock.rb +304 -0
  98. data/lib/garcon/task/safe_task_executor.rb +58 -0
  99. data/lib/garcon/task/single_thread_executor.rb +97 -0
  100. data/lib/garcon/task/thread_pool/cached.rb +71 -0
  101. data/lib/garcon/task/thread_pool/executor.rb +294 -0
  102. data/lib/garcon/task/thread_pool/fixed.rb +61 -0
  103. data/lib/garcon/task/thread_pool/worker.rb +90 -0
  104. data/lib/garcon/task/timer.rb +44 -0
  105. data/lib/garcon/task/timer_set.rb +194 -0
  106. data/lib/garcon/task/timer_task.rb +377 -0
  107. data/lib/garcon/task/waitable_list.rb +58 -0
  108. data/lib/garcon/utility/ansi.rb +199 -0
  109. data/lib/garcon/utility/at_random.rb +77 -0
  110. data/lib/garcon/utility/crypto.rb +292 -0
  111. data/lib/garcon/utility/equalizer.rb +146 -0
  112. data/lib/garcon/utility/faker/extensions/array.rb +22 -0
  113. data/lib/garcon/utility/faker/extensions/symbol.rb +9 -0
  114. data/lib/garcon/utility/faker/faker.rb +164 -0
  115. data/lib/garcon/utility/faker/faker/company.rb +17 -0
  116. data/lib/garcon/utility/faker/faker/hacker.rb +30 -0
  117. data/lib/garcon/utility/faker/faker/version.rb +3 -0
  118. data/lib/garcon/utility/faker/locales/en-US.yml +83 -0
  119. data/lib/garcon/utility/faker/locales/en.yml +21 -0
  120. data/lib/garcon/utility/file_helper.rb +170 -0
  121. data/lib/garcon/utility/hookers.rb +178 -0
  122. data/lib/garcon/utility/interpolation.rb +90 -0
  123. data/lib/garcon/utility/memstash.rb +364 -0
  124. data/lib/garcon/utility/misc.rb +54 -0
  125. data/lib/garcon/utility/msg_from_god.rb +62 -0
  126. data/lib/garcon/utility/retry.rb +238 -0
  127. data/lib/garcon/utility/timeout.rb +58 -0
  128. data/lib/garcon/utility/uber/builder.rb +91 -0
  129. data/lib/garcon/utility/uber/callable.rb +7 -0
  130. data/lib/garcon/utility/uber/delegates.rb +13 -0
  131. data/lib/garcon/utility/uber/inheritable_attr.rb +37 -0
  132. data/lib/garcon/utility/uber/options.rb +101 -0
  133. data/lib/garcon/utility/uber/uber_version.rb +3 -0
  134. data/lib/garcon/utility/uber/version.rb +33 -0
  135. data/lib/garcon/utility/url_helper.rb +100 -0
  136. data/lib/garcon/utils.rb +29 -0
  137. data/lib/garcon/version.rb +62 -0
  138. data/lib/garcun.rb +24 -0
  139. metadata +680 -0
@@ -0,0 +1,128 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Author: Stefano Harding <riddopic@gmail.com>
4
+ # License: Apache License, Version 2.0
5
+ # Copyright: (C) 2014-2015 Stefano Harding
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+
20
+ require 'rbconfig'
21
+ require_relative 'delay'
22
+
23
+ module Garcon
24
+
25
+ class ProcessorCounter
26
+ def initialize
27
+ @processor_count = Delay.new { compute_processor_count }
28
+ @physical_processor_count = Delay.new { compute_physical_count }
29
+ end
30
+
31
+ # Number of processors seen by the OS and used for process scheduling. For
32
+ # performance reasons the calculated value will be memoized on the first
33
+ # call.
34
+ #
35
+ def processor_count
36
+ @processor_count.value
37
+ end
38
+
39
+ # Number of physical processor cores on the current system. For performance
40
+ # reasons the calculated value will be memoized on the first call.
41
+ #
42
+ def physical_processor_count
43
+ @physical_processor_count.value
44
+ end
45
+
46
+ private # P R O P R I E T À P R I V A T A Vietato L'accesso
47
+
48
+ def compute_processor_count
49
+ if RUBY_PLATFORM == 'java'
50
+ java.lang.Runtime.getRuntime.availableProcessors
51
+ else
52
+ os_name = RbConfig::CONFIG["target_os"]
53
+ if os_name =~ /mingw|mswin/
54
+ require 'win32ole'
55
+ result = WIN32OLE.connect("winmgmts://").ExecQuery(
56
+ "select NumberOfLogicalProcessors from Win32_Processor")
57
+ result.to_enum.collect(&:NumberOfLogicalProcessors).reduce(:+)
58
+ elsif File.readable?("/proc/cpuinfo")
59
+ IO.read("/proc/cpuinfo").scan(/^processor/).size
60
+ elsif File.executable?("/usr/bin/hwprefs")
61
+ IO.popen("/usr/bin/hwprefs thread_count").read.to_i
62
+ elsif File.executable?("/usr/sbin/psrinfo")
63
+ IO.popen("/usr/sbin/psrinfo").read.scan(/^.*on-*line/).size
64
+ elsif File.executable?("/usr/sbin/ioscan")
65
+ IO.popen("/usr/sbin/ioscan -kC processor") do |out|
66
+ out.read.scan(/^.*processor/).size
67
+ end
68
+ elsif File.executable?("/usr/sbin/pmcycles")
69
+ IO.popen("/usr/sbin/pmcycles -m").read.count("\n")
70
+ elsif File.executable?("/usr/sbin/lsdev")
71
+ IO.popen("/usr/sbin/lsdev -Cc processor -S 1").read.count("\n")
72
+ elsif File.executable?("/usr/sbin/sysconf") and os_name =~ /irix/i
73
+ IO.popen("/usr/sbin/sysconf NPROC_ONLN").read.to_i
74
+ elsif File.executable?("/usr/sbin/sysctl")
75
+ IO.popen("/usr/sbin/sysctl -n hw.ncpu").read.to_i
76
+ elsif File.executable?("/sbin/sysctl")
77
+ IO.popen("/sbin/sysctl -n hw.ncpu").read.to_i
78
+ else
79
+ 1
80
+ end
81
+ end
82
+ rescue
83
+ return 1
84
+ end
85
+
86
+ def compute_physical_count
87
+ ppc = case RbConfig::CONFIG["target_os"]
88
+ when /darwin1/
89
+ IO.popen("/usr/sbin/sysctl -n hw.physicalcpu").read.to_i
90
+ when /linux/
91
+ cores = {} # unique physical ID / core ID combinations
92
+ phy = 0
93
+ IO.read("/proc/cpuinfo").scan(/^physical id.*|^core id.*/) do |ln|
94
+ if ln.start_with?("physical")
95
+ phy = ln[/\d+/]
96
+ elsif ln.start_with?("core")
97
+ cid = phy + ":" + ln[/\d+/]
98
+ cores[cid] = true if not cores[cid]
99
+ end
100
+ end
101
+ cores.count
102
+ when /mswin|mingw/
103
+ require 'win32ole'
104
+ result_set = WIN32OLE.connect("winmgmts://").ExecQuery(
105
+ "select NumberOfCores from Win32_Processor")
106
+ result_set.to_enum.collect(&:NumberOfCores).reduce(:+)
107
+ else
108
+ processor_count
109
+ end
110
+ # fall back to logical count if physical info is invalid
111
+ ppc > 0 ? ppc : processor_count
112
+ rescue
113
+ return 1
114
+ end
115
+ end
116
+
117
+ # create the default ProcessorCounter on load
118
+ @processor_counter = ProcessorCounter.new
119
+ singleton_class.send :attr_reader, :processor_counter
120
+
121
+ def self.processor_count
122
+ processor_counter.processor_count
123
+ end
124
+
125
+ def self.physical_processor_count
126
+ processor_counter.physical_processor_count
127
+ end
128
+ end
@@ -0,0 +1,304 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Author: Stefano Harding <riddopic@gmail.com>
4
+ # License: Apache License, Version 2.0
5
+ # Copyright: (C) 2014-2015 Stefano Harding
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+
20
+ require_relative 'atomic'
21
+
22
+ module Garcon
23
+
24
+ # read-write Lock for cooking safety.
25
+ #
26
+ # Allows any number of concurrent readers, but only one concurrent writer
27
+ # (And if the "write" lock is taken, any readers who come along will have to
28
+ # wait). If readers are already active when a writer comes along, the writer
29
+ # will wait for all the readers to finish before going ahead. Any additional
30
+ # readers that come when the writer is already waiting, will also wait (so
31
+ # writers are not starved).
32
+ #
33
+ # @example
34
+ # lock = Garcon::ReadWriteLock.new
35
+ # lock.with_read_lock { data.retrieve }
36
+ # lock.with_write_lock { data.modify! }
37
+ #
38
+ # @note
39
+ # Do **not** try to acquire the write lock while already holding a read lock
40
+ # **or** try to acquire the write lock while you already have it.
41
+ # This will lead to deadlock
42
+ #
43
+ class ReadWriteLock
44
+
45
+ # @!visibility private
46
+ WAITING_WRITER = 1 << 15
47
+
48
+ # @!visibility private
49
+ RUNNING_WRITER = 1 << 30
50
+
51
+ # @!visibility private
52
+ MAX_READERS = WAITING_WRITER - 1
53
+
54
+ # @!visibility private
55
+ MAX_WRITERS = RUNNING_WRITER - MAX_READERS - 1
56
+
57
+ # Implementation notes:
58
+ # * A goal is to make the uncontended path for both readers/writers
59
+ # lock-free.
60
+ # * Only if there is reader-writer or writer-writer contention, should
61
+ # locks be used.
62
+ # * Internal state is represented by a single integer ("counter"), and
63
+ # updated using atomic compare-and-swap operations.
64
+ # * When the counter is 0, the lock is free.
65
+ # * Each reader increments the counter by 1 when acquiring a read lock (and
66
+ # decrements by 1 when releasing the read lock).
67
+ # * The counter is increased by (1 << 15) for each writer waiting to
68
+ # acquire the write lock, and by (1 << 30) if the write lock is taken.
69
+
70
+ # Create a new `ReadWriteLock` in the unlocked state.
71
+ #
72
+ def initialize
73
+ @counter = AtomicMutex.new(0) # represents lock state
74
+ @reader_q = ConditionVariable.new # queue for waiting readers
75
+ @reader_mutex = Mutex.new # to protect reader queue
76
+ @writer_q = ConditionVariable.new # queue for waiting writers
77
+ @writer_mutex = Mutex.new # to protect writer queue
78
+ end
79
+
80
+ # Execute a block operation within a read lock.
81
+ #
82
+ # @return [Object]
83
+ # The result of the block operation.
84
+ #
85
+ # @yield the task to be performed within the lock.
86
+ #
87
+ # @raise [ArgumentError]
88
+ # When no block is given.
89
+ #
90
+ # @raise [Garcon::ResourceLimitError]
91
+ # If the maximum number of readers is exceeded.
92
+ #
93
+ def with_read_lock
94
+ raise ArgumentError, 'no block given' unless block_given?
95
+ acquire_read_lock
96
+ begin
97
+ yield
98
+ ensure
99
+ release_read_lock
100
+ end
101
+ end
102
+
103
+ # Execute a block operation within a write lock.
104
+ #
105
+ # @return [Object] the result of the block operation.
106
+ #
107
+ # @yield the task to be performed within the lock.
108
+ #
109
+ # @raise [ArgumentError]
110
+ # When no block is given.
111
+ #
112
+ # @raise [Garcon::ResourceLimitError]
113
+ # If the maximum number of readers is exceeded.
114
+ #
115
+ def with_write_lock
116
+ raise ArgumentError, 'no block given' unless block_given?
117
+ acquire_write_lock
118
+ begin
119
+ yield
120
+ ensure
121
+ release_write_lock
122
+ end
123
+ end
124
+
125
+ # Acquire a read lock. If a write lock has been acquired will block until
126
+ # it is released. Will not block if other read locks have been acquired.
127
+ #
128
+ # @return [Boolean]
129
+ # True if the lock is successfully acquired.
130
+ #
131
+ # @raise [Garcon::ResourceLimitError]
132
+ # If the maximum number of readers is exceeded.
133
+ #
134
+ def acquire_read_lock
135
+ while(true)
136
+ c = @counter.value
137
+ raise ResourceLimitError, 'Too many reader threads' if max_readers?(c)
138
+
139
+ if waiting_writer?(c)
140
+ @reader_mutex.synchronize do
141
+ @reader_q.wait(@reader_mutex) if waiting_writer?
142
+ end
143
+
144
+ while(true)
145
+ c = @counter.value
146
+ if running_writer?(c)
147
+ @reader_mutex.synchronize do
148
+ @reader_q.wait(@reader_mutex) if running_writer?
149
+ end
150
+ else
151
+ return if @counter.compare_and_swap(c,c+1)
152
+ end
153
+ end
154
+ else
155
+ break if @counter.compare_and_swap(c,c+1)
156
+ end
157
+ end
158
+ true
159
+ end
160
+
161
+ # Release a previously acquired read lock.
162
+ #
163
+ # @return [Boolean]
164
+ # True if the lock is successfully released.
165
+ #
166
+ def release_read_lock
167
+ while(true)
168
+ c = @counter.value
169
+ if @counter.compare_and_swap(c,c-1)
170
+ if waiting_writer?(c) && running_readers(c) == 1
171
+ @writer_mutex.synchronize { @writer_q.signal }
172
+ end
173
+ break
174
+ end
175
+ end
176
+ true
177
+ end
178
+
179
+ # Acquire a write lock. Will block and wait for all active readers and
180
+ # writers.
181
+ #
182
+ # @return [Boolean]
183
+ # True if the lock is successfully acquired.
184
+ #
185
+ # @raise [Garcon::ResourceLimitError]
186
+ # If the maximum number of writers is exceeded.
187
+ #
188
+ def acquire_write_lock
189
+ while(true)
190
+ c = @counter.value
191
+ raise ResourceLimitError, 'Too many writer threads' if max_writers?(c)
192
+
193
+ if c == 0
194
+ break if @counter.compare_and_swap(0,RUNNING_WRITER)
195
+ elsif @counter.compare_and_swap(c,c+WAITING_WRITER)
196
+ while(true)
197
+ @writer_mutex.synchronize do
198
+ c = @counter.value
199
+ if running_writer?(c) || running_readers?(c)
200
+ @writer_q.wait(@writer_mutex)
201
+ end
202
+ end
203
+
204
+ c = @counter.value
205
+ break if !running_writer?(c) && !running_readers?(c) &&
206
+ @counter.compare_and_swap(c,c+RUNNING_WRITER-WAITING_WRITER)
207
+ end
208
+ break
209
+ end
210
+ end
211
+ true
212
+ end
213
+
214
+ # Release a previously acquired write lock.
215
+ #
216
+ # @return [Boolean]
217
+ # True if the lock is successfully released.
218
+ #
219
+ def release_write_lock
220
+ while(true)
221
+ c = @counter.value
222
+ if @counter.compare_and_swap(c,c-RUNNING_WRITER)
223
+ @reader_mutex.synchronize { @reader_q.broadcast }
224
+ if waiting_writers(c) > 0
225
+ @writer_mutex.synchronize { @writer_q.signal }
226
+ end
227
+ break
228
+ end
229
+ end
230
+ true
231
+ end
232
+
233
+ # Returns a string representing *obj*. Includes the current reader and
234
+ # writer counts.
235
+ #
236
+ def to_s
237
+ c = @counter.value
238
+ s = if running_writer?(c)
239
+ "1 writer running, "
240
+ elsif running_readers(c) > 0
241
+ "#{running_readers(c)} readers running, "
242
+ else
243
+ ""
244
+ end
245
+
246
+ "#<ReadWriteLock:#{object_id.to_s(16)} #{s}#{waiting_writers(c)} writers waiting>"
247
+ end
248
+
249
+ # Queries if the write lock is held by any thread.
250
+ #
251
+ # @return [Boolean]
252
+ # True if the write lock is held else false.
253
+ #
254
+ def write_locked?
255
+ @counter.value >= RUNNING_WRITER
256
+ end
257
+
258
+ # Queries whether any threads are waiting to acquire the read or write lock.
259
+ #
260
+ # @return [Boolean]
261
+ # True if any threads are waiting for a lock else false.
262
+ #
263
+ def has_waiters?
264
+ waiting_writer?(@counter.value)
265
+ end
266
+
267
+ private # P R O P R I E T À P R I V A T A Vietato L'accesso
268
+
269
+ # @!visibility private
270
+ def running_readers(c = @counter.value)
271
+ c & MAX_READERS
272
+ end
273
+
274
+ # @!visibility private
275
+ def running_readers?(c = @counter.value)
276
+ (c & MAX_READERS) > 0
277
+ end
278
+
279
+ # @!visibility private
280
+ def running_writer?(c = @counter.value)
281
+ c >= RUNNING_WRITER
282
+ end
283
+
284
+ # @!visibility private
285
+ def waiting_writers(c = @counter.value)
286
+ (c & MAX_WRITERS) / WAITING_WRITER
287
+ end
288
+
289
+ # @!visibility private
290
+ def waiting_writer?(c = @counter.value)
291
+ c >= WAITING_WRITER
292
+ end
293
+
294
+ # @!visibility private
295
+ def max_readers?(c = @counter.value)
296
+ (c & MAX_READERS) == MAX_READERS
297
+ end
298
+
299
+ # @!visibility private
300
+ def max_writers?(c = @counter.value)
301
+ (c & MAX_WRITERS) == MAX_WRITERS
302
+ end
303
+ end
304
+ end
@@ -0,0 +1,58 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Author: Stefano Harding <riddopic@gmail.com>
4
+ # License: Apache License, Version 2.0
5
+ # Copyright: (C) 2014-2015 Stefano Harding
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+
20
+ require 'thread'
21
+
22
+ module Garcon
23
+
24
+ # A simple utility class that executes a callable and returns and array of
25
+ # three elements:
26
+ # * success: indicating if the callable has been executed without errors
27
+ # * value: filled by the callable result if it has been executed without
28
+ # errors, nil otherwise
29
+ # * reason: the error risen by the callable if it has been executed with
30
+ # errors, nil otherwise
31
+ #
32
+ class SafeTaskExecutor
33
+
34
+ def initialize(task, opts = {})
35
+ @task = task
36
+ @mutex = Mutex.new
37
+ @ex = opts.fetch(:rescue_exception, false) ? Exception : StandardError
38
+ end
39
+
40
+ # @return [Array]
41
+ def execute(*args)
42
+ @mutex.synchronize do
43
+ success = false
44
+ value = reason = nil
45
+
46
+ begin
47
+ value = @task.call(*args)
48
+ success = true
49
+ rescue @ex => e
50
+ reason = e
51
+ success = false
52
+ end
53
+
54
+ [success, value, reason]
55
+ end
56
+ end
57
+ end
58
+ end