synapse-core 0.5.6 → 0.6.0
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.
- checksums.yaml +7 -0
- data/lib/synapse-core.rb +31 -1
- data/lib/synapse/command.rb +1 -0
- data/lib/synapse/command/callbacks/future.rb +3 -3
- data/lib/synapse/command/callbacks/void.rb +14 -0
- data/lib/synapse/command/command_bus.rb +2 -2
- data/lib/synapse/command/command_callback.rb +9 -2
- data/lib/synapse/command/gateway.rb +1 -1
- data/lib/synapse/command/gateway/interval_retry_scheduler.rb +6 -6
- data/lib/synapse/command/gateway/retry_scheduler.rb +7 -4
- data/lib/synapse/command/interceptor_chain.rb +1 -1
- data/lib/synapse/command/interceptors/serialization.rb +2 -1
- data/lib/synapse/command/simple_command_bus.rb +23 -34
- data/lib/synapse/common.rb +2 -2
- data/lib/synapse/common/concurrency/disposable_lock.rb +157 -0
- data/lib/synapse/common/concurrency/identifier_lock_manager.rb +164 -0
- data/lib/synapse/common/duplication.rb +4 -4
- data/lib/synapse/common/errors.rb +5 -0
- data/lib/synapse/configuration/container.rb +1 -1
- data/lib/synapse/configuration/container_builder.rb +1 -1
- data/lib/synapse/configuration/definition.rb +1 -1
- data/lib/synapse/domain/aggregate_root.rb +1 -1
- data/lib/synapse/domain/simple_stream.rb +3 -5
- data/lib/synapse/domain/stream.rb +2 -2
- data/lib/synapse/event_bus/event_bus.rb +2 -2
- data/lib/synapse/event_bus/simple_event_bus.rb +5 -6
- data/lib/synapse/event_sourcing/caching.rb +1 -1
- data/lib/synapse/event_sourcing/entity.rb +4 -2
- data/lib/synapse/event_sourcing/repository.rb +9 -13
- data/lib/synapse/event_sourcing/snapshot/taker.rb +1 -1
- data/lib/synapse/mapping/mapping.rb +1 -1
- data/lib/synapse/process_manager/correlation.rb +3 -29
- data/lib/synapse/process_manager/pessimistic_lock_manager.rb +3 -3
- data/lib/synapse/process_manager/process.rb +2 -6
- data/lib/synapse/process_manager/process_manager.rb +1 -1
- data/lib/synapse/process_manager/process_repository.rb +1 -1
- data/lib/synapse/process_manager/repository/in_memory.rb +5 -4
- data/lib/synapse/process_manager/simple_process_manager.rb +2 -2
- data/lib/synapse/repository/errors.rb +2 -2
- data/lib/synapse/repository/locking.rb +48 -0
- data/lib/synapse/repository/optimistic_lock_manager.rb +10 -9
- data/lib/synapse/repository/pessimistic_lock_manager.rb +5 -4
- data/lib/synapse/repository/repository.rb +1 -1
- data/lib/synapse/repository/simple_repository.rb +8 -7
- data/lib/synapse/serialization/converter.rb +3 -0
- data/lib/synapse/serialization/converter_factory.rb +6 -5
- data/lib/synapse/serialization/serialized_object.rb +4 -4
- data/lib/synapse/serialization/serialized_type.rb +4 -4
- data/lib/synapse/uow/listener_collection.rb +12 -9
- data/lib/synapse/uow/provider.rb +1 -1
- data/lib/synapse/uow/uow.rb +1 -1
- data/lib/synapse/upcasting/upcaster_chain.rb +1 -1
- data/lib/synapse/version.rb +1 -1
- data/test/command/serialization_test.rb +5 -2
- data/test/command/simple_command_bus_test.rb +9 -16
- data/test/command/validation_test.rb +1 -1
- data/test/common/concurrency/identifier_lock_manager_test.rb +137 -0
- data/test/configuration/component/serialization/converter_factory_test.rb +2 -2
- data/test/event_sourcing/repository_test.rb +18 -0
- data/test/repository/simple_repository_test.rb +42 -10
- data/test/test_helper.rb +3 -4
- metadata +25 -29
- data/lib/synapse.rb +0 -34
- data/lib/synapse/common/concurrency/identifier_lock.rb +0 -56
- data/lib/synapse/common/concurrency/public_lock.rb +0 -95
- data/lib/synapse/event_bus/clustering/cluster.rb +0 -10
- data/lib/synapse/event_bus/clustering/event_bus.rb +0 -55
- data/lib/synapse/event_bus/clustering/selector.rb +0 -14
- data/lib/synapse/rails/injection_helper.rb +0 -23
- data/lib/synapse/railtie.rb +0 -17
- data/test/common/concurrency/identifier_lock_test.rb +0 -25
- data/test/common/concurrency/public_lock_test.rb +0 -83
- data/test/process_manager/correlation_test.rb +0 -24
- data/test/rails/injection_helper_test.rb +0 -27
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0ecce43088ffbcd564924205697ffcf99a1b5c7d
|
4
|
+
data.tar.gz: 7366f73d7fb0ff57bb7f786b80615beaa6de0ccc
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 74a8511d2dcff70321d63c0dc54c6c170cf63bb2c710e70bebdbbc1996bd81afb8e5cc799d7d7f99240a937b806924239ae0a5e2ca719c37191e73dcba8efb6d
|
7
|
+
data.tar.gz: 7d2af413072cd726cdbab5c9775692a691c7505c12b4b2ed9a872ceec4b335fd26d788b330c00f9c8740e5a4675d3ebb48d7a8ac5ce0b5a80a4c22b676d0ce0c
|
data/lib/synapse-core.rb
CHANGED
@@ -1 +1,31 @@
|
|
1
|
-
require '
|
1
|
+
require 'active_support'
|
2
|
+
require 'active_support/core_ext'
|
3
|
+
require 'atomic'
|
4
|
+
require 'contender'
|
5
|
+
require 'forwardable'
|
6
|
+
require 'logging'
|
7
|
+
require 'ref'
|
8
|
+
require 'set'
|
9
|
+
|
10
|
+
require 'synapse/common'
|
11
|
+
require 'synapse/version'
|
12
|
+
|
13
|
+
module Synapse
|
14
|
+
# Core components
|
15
|
+
autoload :Command, 'synapse/command'
|
16
|
+
autoload :Domain, 'synapse/domain'
|
17
|
+
autoload :EventBus, 'synapse/event_bus'
|
18
|
+
autoload :Mapping, 'synapse/mapping'
|
19
|
+
autoload :Repository, 'synapse/repository'
|
20
|
+
autoload :Serialization, 'synapse/serialization'
|
21
|
+
autoload :UnitOfWork, 'synapse/uow'
|
22
|
+
|
23
|
+
# Optional components
|
24
|
+
autoload :Auditing, 'synapse/auditing'
|
25
|
+
autoload :Configuration, 'synapse/configuration'
|
26
|
+
autoload :EventSourcing, 'synapse/event_sourcing'
|
27
|
+
autoload :EventStore, 'synapse/event_store'
|
28
|
+
autoload :ProcessManager, 'synapse/process_manager'
|
29
|
+
autoload :Upcasting, 'synapse/upcasting'
|
30
|
+
end
|
31
|
+
|
data/lib/synapse/command.rb
CHANGED
@@ -5,6 +5,8 @@ module Synapse
|
|
5
5
|
def initialize
|
6
6
|
@mutex = Mutex.new
|
7
7
|
@condition = ConditionVariable.new
|
8
|
+
|
9
|
+
@dispatched = false
|
8
10
|
end
|
9
11
|
|
10
12
|
# @raise [Exception] If an exception occured during command execution
|
@@ -16,9 +18,7 @@ module Synapse
|
|
16
18
|
@condition.wait @mutex, timeout
|
17
19
|
end
|
18
20
|
|
19
|
-
if @exception
|
20
|
-
raise @exception
|
21
|
-
end
|
21
|
+
raise @exception if @exception
|
22
22
|
|
23
23
|
@result
|
24
24
|
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Synapse
|
2
|
+
module Command
|
3
|
+
# Implementation of a command callback that does nothing
|
4
|
+
class VoidCallback < CommandCallback
|
5
|
+
# @param [Object] result The result from the command handler
|
6
|
+
# @return [undefined]
|
7
|
+
def on_success(result); end
|
8
|
+
|
9
|
+
# @param [Exception] exception The cause of the failure
|
10
|
+
# @return [undefined]
|
11
|
+
def on_failure(exception); end
|
12
|
+
end # VoidCallback
|
13
|
+
end # Command
|
14
|
+
end
|
@@ -34,7 +34,7 @@ module Synapse
|
|
34
34
|
#
|
35
35
|
# @param [Class] command_type
|
36
36
|
# @param [CommandHandler] handler
|
37
|
-
# @return [
|
37
|
+
# @return [CommandHandler] The command handler being replaced, if any
|
38
38
|
def subscribe(command_type, handler)
|
39
39
|
raise NotImplementedError
|
40
40
|
end
|
@@ -44,7 +44,7 @@ module Synapse
|
|
44
44
|
#
|
45
45
|
# @param [Class] command_type
|
46
46
|
# @param [CommandHandler] handler
|
47
|
-
# @return [
|
47
|
+
# @return [Boolean] True if command handler was unsubscribed from command handler
|
48
48
|
def unsubscribe(command_type, handler)
|
49
49
|
raise NotImplementedError
|
50
50
|
end
|
@@ -1,18 +1,25 @@
|
|
1
1
|
module Synapse
|
2
2
|
module Command
|
3
3
|
# Callback that is notified of the outcome of the dispatch of a command
|
4
|
+
# @abstract
|
4
5
|
class CommandCallback
|
5
6
|
# Called when a dispatch is successful
|
6
7
|
#
|
8
|
+
# @abstract
|
7
9
|
# @param [Object] result The result from the command handler
|
8
10
|
# @return [undefined]
|
9
|
-
def on_success(result)
|
11
|
+
def on_success(result)
|
12
|
+
raise NotImplementedError
|
13
|
+
end
|
10
14
|
|
11
15
|
# Called when a dispatch fails due to an exception
|
12
16
|
#
|
17
|
+
# @abstract
|
13
18
|
# @param [Exception] exception The cause of the failure
|
14
19
|
# @return [undefined]
|
15
|
-
def on_failure(exception)
|
20
|
+
def on_failure(exception)
|
21
|
+
raise NotImplementedError
|
22
|
+
end
|
16
23
|
end # CommandCallback
|
17
24
|
end # Command
|
18
25
|
end
|
@@ -8,17 +8,17 @@ module Synapse
|
|
8
8
|
# This implementation uses EventMachine to schedule one-shot timers.
|
9
9
|
class IntervalRetryScheduler < RetryScheduler
|
10
10
|
# @param [Float] interval
|
11
|
-
# @param [Integer]
|
11
|
+
# @param [Integer] max_retries
|
12
12
|
# @return [undefined]
|
13
|
-
def initialize(interval,
|
13
|
+
def initialize(interval, max_retries)
|
14
14
|
@interval = interval
|
15
|
-
@
|
15
|
+
@max_retries = max_retries
|
16
16
|
|
17
17
|
@logger = Logging.logger[self.class]
|
18
18
|
end
|
19
19
|
|
20
20
|
# @param [CommandMessage] command
|
21
|
-
# @param [Array] failures
|
21
|
+
# @param [Array<Exception>] failures
|
22
22
|
# @param [Proc] dispatcher
|
23
23
|
# @return [Boolean]
|
24
24
|
def schedule(command, failures, dispatcher)
|
@@ -33,7 +33,7 @@ module Synapse
|
|
33
33
|
|
34
34
|
failureCount = failures.size
|
35
35
|
|
36
|
-
if failureCount > @
|
36
|
+
if failureCount > @max_retries
|
37
37
|
@logger.info 'Dispatch of command [%s] [%s] resulted in exception [%s] times' %
|
38
38
|
[command.payload_type, command.id, failureCount]
|
39
39
|
|
@@ -42,7 +42,7 @@ module Synapse
|
|
42
42
|
|
43
43
|
if @logger.info?
|
44
44
|
@logger.info 'Dispatch of command [%s] [%s] resulted in exception; will retry up to [%s] more times' %
|
45
|
-
[command.payload_type, command.id, @
|
45
|
+
[command.payload_type, command.id, @max_retries - failureCount]
|
46
46
|
end
|
47
47
|
|
48
48
|
perform_schedule command, dispatcher
|
@@ -16,11 +16,14 @@ module Synapse
|
|
16
16
|
# the failure will be interpreted as terminal and the callback will be invoked with the
|
17
17
|
# last recorded failure.
|
18
18
|
#
|
19
|
+
# @abstract
|
19
20
|
# @param [CommandMessage] command
|
20
|
-
# @param [Array] failures
|
21
|
+
# @param [Array<Exception>] failures
|
21
22
|
# @param [Proc] dispatcher
|
22
23
|
# @return [Boolean]
|
23
|
-
def schedule(command, failures, dispatcher)
|
24
|
-
|
25
|
-
|
24
|
+
def schedule(command, failures, dispatcher)
|
25
|
+
raise NotImplementedError
|
26
|
+
end
|
27
|
+
end # RetryScheduler
|
28
|
+
end # Command
|
26
29
|
end
|
@@ -8,7 +8,7 @@ module Synapse
|
|
8
8
|
# command message that will be passed on in the chain.
|
9
9
|
class InterceptorChain
|
10
10
|
# @param [UnitOfWork] unit The current unit of work for this command dispatch
|
11
|
-
# @param [Array] interceptors
|
11
|
+
# @param [Array<DispatchInterceptor>] interceptors
|
12
12
|
# @param [CommandHandler] handler
|
13
13
|
# @return [undefined]
|
14
14
|
def initialize(unit, interceptors, handler)
|
@@ -4,6 +4,7 @@ module Synapse
|
|
4
4
|
# serialization-aware message. This provides optimization in cases where storage (in an event
|
5
5
|
# store) and publication (on the event bus) use the same serialization mechansim.
|
6
6
|
class SerializationOptimizingInterceptor < DispatchInterceptor
|
7
|
+
# @return [undefined]
|
7
8
|
def initialize
|
8
9
|
@listener = SerializationOptimizingListener.new
|
9
10
|
end
|
@@ -32,4 +33,4 @@ module Synapse
|
|
32
33
|
end
|
33
34
|
end # SerializationOptimizingListener
|
34
35
|
end
|
35
|
-
end
|
36
|
+
end
|
@@ -6,10 +6,10 @@ module Synapse
|
|
6
6
|
# @return [RollbackPolicy]
|
7
7
|
attr_accessor :rollback_policy
|
8
8
|
|
9
|
-
# @return [Array]
|
9
|
+
# @return [Array<CommandFilter>]
|
10
10
|
attr_reader :filters
|
11
11
|
|
12
|
-
# @return [Array]
|
12
|
+
# @return [Array<DispatchInterceptor>]
|
13
13
|
attr_reader :interceptors
|
14
14
|
|
15
15
|
# @param [UnitOfWorkFactory] unit_factory
|
@@ -30,7 +30,7 @@ module Synapse
|
|
30
30
|
# @param [CommandMessage] command
|
31
31
|
# @return [undefined]
|
32
32
|
def dispatch(command)
|
33
|
-
dispatch_with_callback command,
|
33
|
+
dispatch_with_callback command, VoidCallback.new
|
34
34
|
end
|
35
35
|
|
36
36
|
# @api public
|
@@ -42,9 +42,9 @@ module Synapse
|
|
42
42
|
result = perform_dispatch command
|
43
43
|
callback.on_success result
|
44
44
|
rescue => exception
|
45
|
-
backtrace = exception.backtrace.join
|
46
|
-
@logger.error
|
47
|
-
|
45
|
+
backtrace = exception.backtrace.join $RS
|
46
|
+
@logger.error "Exception occured while dispatching command {#{command.payload_type}} {#{command.id}}:\n" +
|
47
|
+
"#{exception.inspect} #{backtrace}"
|
48
48
|
|
49
49
|
callback.on_failure exception
|
50
50
|
end
|
@@ -53,39 +53,29 @@ module Synapse
|
|
53
53
|
# @api public
|
54
54
|
# @param [Class] command_type
|
55
55
|
# @param [CommandHandler] handler
|
56
|
-
# @return [
|
56
|
+
# @return [CommandHandler] The command handler being replaced, if any
|
57
57
|
def subscribe(command_type, handler)
|
58
|
-
|
59
|
-
current_handler = @handlers.fetch command_type
|
60
|
-
@logger.info 'Command handler [%s] is being replaced by [%s] for command type [%s]' %
|
61
|
-
[current_handler.class, handler.class, command_type]
|
62
|
-
else
|
63
|
-
@logger.debug 'Command handler [%s] subscribed to command type [%s]' %
|
64
|
-
[handler.class, command_type]
|
65
|
-
end
|
58
|
+
current = @handlers.fetch command_type, nil
|
66
59
|
|
67
60
|
@handlers.store command_type, handler
|
61
|
+
@logger.debug "Command handler {#{handler.class}} subscribed to command type {#{command_type}}"
|
62
|
+
|
63
|
+
current
|
68
64
|
end
|
69
65
|
|
70
66
|
# @api public
|
71
67
|
# @param [Class] command_type
|
72
68
|
# @param [CommandHandler] handler
|
73
|
-
# @return [
|
69
|
+
# @return [Boolean] True if command handler was unsubscribed from command handler
|
74
70
|
def unsubscribe(command_type, handler)
|
75
|
-
|
76
|
-
current_handler = @handlers.fetch command_type
|
77
|
-
if current_handler.equal? handler
|
78
|
-
@handlers.delete command_type
|
71
|
+
current = @handlers.fetch command_type, nil
|
79
72
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
else
|
87
|
-
@logger.info 'Command type [%s] not subscribed to any handler' % command_type
|
88
|
-
end
|
73
|
+
return false unless current === handler
|
74
|
+
|
75
|
+
@handlers.delete command_type
|
76
|
+
@logger.debug "Command handler {#{handler.class}} unsubscribed from command type {#{command_type}}"
|
77
|
+
|
78
|
+
return true
|
89
79
|
end
|
90
80
|
|
91
81
|
protected
|
@@ -107,8 +97,7 @@ module Synapse
|
|
107
97
|
chain = InterceptorChain.new unit, @interceptors, handler
|
108
98
|
|
109
99
|
begin
|
110
|
-
@logger.info
|
111
|
-
[command.id, command.payload_type, handler.class]
|
100
|
+
@logger.info "Dispatching command {#{command.id}} {#{command.payload_type}} to handler {#{handler.class}}"
|
112
101
|
|
113
102
|
result = chain.proceed command
|
114
103
|
rescue => exception
|
@@ -132,12 +121,12 @@ module Synapse
|
|
132
121
|
# @param [CommandMessage] command
|
133
122
|
# @return [CommandHandler]
|
134
123
|
def handler_for(command)
|
135
|
-
|
124
|
+
command_type = command.payload_type
|
136
125
|
|
137
126
|
begin
|
138
|
-
@handlers.fetch
|
127
|
+
@handlers.fetch command_type
|
139
128
|
rescue KeyError
|
140
|
-
raise NoHandlerError,
|
129
|
+
raise NoHandlerError, "No handler subscribed for command {#{command_type}}"
|
141
130
|
end
|
142
131
|
end
|
143
132
|
end # SimpleCommandBus
|
data/lib/synapse/common.rb
CHANGED
@@ -3,7 +3,7 @@ require 'synapse/common/identifier'
|
|
3
3
|
require 'synapse/common/message'
|
4
4
|
require 'synapse/common/message_builder'
|
5
5
|
|
6
|
-
require 'synapse/common/concurrency/
|
7
|
-
require 'synapse/common/concurrency/
|
6
|
+
require 'synapse/common/concurrency/disposable_lock'
|
7
|
+
require 'synapse/common/concurrency/identifier_lock_manager'
|
8
8
|
|
9
9
|
require 'synapse/common/duplication'
|
@@ -0,0 +1,157 @@
|
|
1
|
+
module Synapse
|
2
|
+
# @api private
|
3
|
+
class DisposableLock
|
4
|
+
# @return [Boolean]
|
5
|
+
attr_reader :closed
|
6
|
+
|
7
|
+
alias_method :closed?, :closed
|
8
|
+
|
9
|
+
# @return [Thread]
|
10
|
+
attr_reader :owner
|
11
|
+
|
12
|
+
# @return [Array]
|
13
|
+
attr_reader :waiters
|
14
|
+
|
15
|
+
# @return [undefined]
|
16
|
+
def initialize
|
17
|
+
@mutex = Mutex.new
|
18
|
+
|
19
|
+
@closed = false
|
20
|
+
@hold_count = 0
|
21
|
+
@owner = nil
|
22
|
+
@waiters = Array.new
|
23
|
+
end
|
24
|
+
|
25
|
+
# @return [Boolean]
|
26
|
+
def owned?
|
27
|
+
@owner == Thread.current
|
28
|
+
end
|
29
|
+
|
30
|
+
# @param [Thread] thread
|
31
|
+
# @return [Boolean]
|
32
|
+
def owned_by?(thread)
|
33
|
+
@owner == thread
|
34
|
+
end
|
35
|
+
|
36
|
+
# @return [Boolean]
|
37
|
+
def locked?
|
38
|
+
@hold_count > 0
|
39
|
+
end
|
40
|
+
|
41
|
+
# @return [Boolean] False if lock has been closed
|
42
|
+
def lock
|
43
|
+
@mutex.synchronize do
|
44
|
+
unless owned?
|
45
|
+
if @hold_count == 0
|
46
|
+
@owner = Thread.current
|
47
|
+
else
|
48
|
+
@waiters.push Thread.current
|
49
|
+
|
50
|
+
begin
|
51
|
+
wait_for_lock
|
52
|
+
ensure
|
53
|
+
@waiters.delete Thread.current
|
54
|
+
end
|
55
|
+
|
56
|
+
return unless owned?
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
@hold_count += 1
|
61
|
+
end
|
62
|
+
|
63
|
+
if closed?
|
64
|
+
unlock
|
65
|
+
return false
|
66
|
+
end
|
67
|
+
|
68
|
+
return true
|
69
|
+
end
|
70
|
+
|
71
|
+
# @return [Boolean]
|
72
|
+
def try_lock
|
73
|
+
@mutex.synchronize do
|
74
|
+
unless owned?
|
75
|
+
if @hold_count == 0
|
76
|
+
@owner = Thread.current
|
77
|
+
else
|
78
|
+
return false
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
@hold_count += 1
|
83
|
+
return true
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# @raise [RuntimeError] If caller does not own the lock
|
88
|
+
# @return [undefined]
|
89
|
+
def unlock
|
90
|
+
@mutex.synchronize do
|
91
|
+
raise RuntimeError unless owned?
|
92
|
+
|
93
|
+
@hold_count -= 1
|
94
|
+
|
95
|
+
if @hold_count == 0
|
96
|
+
@owner = nil
|
97
|
+
wakeup_next_waiter
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# @return [Boolean] True if lock was closed
|
103
|
+
def try_close
|
104
|
+
return false unless try_lock
|
105
|
+
|
106
|
+
begin
|
107
|
+
if @hold_count == 1
|
108
|
+
@closed = true
|
109
|
+
return true
|
110
|
+
end
|
111
|
+
|
112
|
+
return false
|
113
|
+
ensure
|
114
|
+
unlock
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
private
|
119
|
+
|
120
|
+
# @raise [DeadlockError]
|
121
|
+
# @return [undefined]
|
122
|
+
def check_for_deadlock
|
123
|
+
return if owned?
|
124
|
+
return unless locked?
|
125
|
+
|
126
|
+
for waiter in IdentifierLockManager.waiters_for_locks_owned_by(Thread.current)
|
127
|
+
if owned_by? waiter
|
128
|
+
raise DeadlockError
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
# Mutex must be locked to perform this operation
|
134
|
+
# @return [undefined]
|
135
|
+
def wait_for_lock
|
136
|
+
loop do
|
137
|
+
if @hold_count == 0
|
138
|
+
@owner = Thread.current
|
139
|
+
return
|
140
|
+
end
|
141
|
+
|
142
|
+
check_for_deadlock
|
143
|
+
@mutex.sleep 0.1 # Sleep for 100 milliseconds
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
# @return [undefined]
|
148
|
+
def wakeup_next_waiter
|
149
|
+
begin
|
150
|
+
n = @waiters.shift
|
151
|
+
n.wakeup if n
|
152
|
+
rescue ThreadError
|
153
|
+
retry
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end # DisposableLock
|
157
|
+
end
|