cassandra-driver 1.0.0.rc.1-java → 1.1.0-java
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 +4 -4
- data/README.md +58 -18
- data/lib/cassandra.rb +132 -93
- data/lib/cassandra/auth.rb +3 -3
- data/lib/cassandra/cluster.rb +65 -39
- data/lib/cassandra/cluster/client.rb +67 -28
- data/lib/cassandra/{client/connection_manager.rb → cluster/connection_pool.rb} +9 -3
- data/lib/cassandra/cluster/connector.rb +101 -30
- data/lib/cassandra/cluster/control_connection.rb +160 -96
- data/lib/cassandra/{client/null_logger.rb → cluster/failed_connection.rb} +12 -14
- data/lib/cassandra/cluster/options.rb +26 -11
- data/lib/cassandra/cluster/schema.rb +22 -1
- data/lib/cassandra/column.rb +5 -0
- data/lib/cassandra/driver.rb +46 -12
- data/lib/cassandra/errors.rb +5 -5
- data/lib/cassandra/execution/options.rb +42 -8
- data/lib/cassandra/execution/trace.rb +4 -4
- data/lib/cassandra/executors.rb +111 -0
- data/lib/cassandra/future.rb +88 -64
- data/lib/cassandra/keyspace.rb +12 -0
- data/lib/cassandra/load_balancing.rb +10 -0
- data/lib/cassandra/load_balancing/policies/dc_aware_round_robin.rb +10 -5
- data/lib/cassandra/load_balancing/policies/round_robin.rb +7 -5
- data/lib/cassandra/load_balancing/policies/token_aware.rb +31 -10
- data/lib/cassandra/load_balancing/policies/white_list.rb +4 -7
- data/lib/cassandra/null_logger.rb +35 -0
- data/lib/cassandra/protocol/cql_protocol_handler.rb +8 -1
- data/lib/cassandra/protocol/requests/query_request.rb +1 -11
- data/lib/cassandra/result.rb +34 -9
- data/lib/cassandra/session.rb +6 -0
- data/lib/cassandra/statements/prepared.rb +5 -1
- data/lib/cassandra/table.rb +5 -0
- data/lib/cassandra/util.rb +130 -0
- data/lib/cassandra/version.rb +1 -1
- metadata +40 -50
- data/lib/cassandra/client.rb +0 -144
- data/lib/cassandra/client/batch.rb +0 -212
- data/lib/cassandra/client/client.rb +0 -591
- data/lib/cassandra/client/column_metadata.rb +0 -54
- data/lib/cassandra/client/connector.rb +0 -273
- data/lib/cassandra/client/execute_options_decoder.rb +0 -59
- data/lib/cassandra/client/peer_discovery.rb +0 -50
- data/lib/cassandra/client/prepared_statement.rb +0 -314
- data/lib/cassandra/client/query_result.rb +0 -230
- data/lib/cassandra/client/request_runner.rb +0 -70
- data/lib/cassandra/client/result_metadata.rb +0 -48
- data/lib/cassandra/client/void_result.rb +0 -78
@@ -23,23 +23,38 @@ module Cassandra
|
|
23
23
|
attr_reader :credentials, :auth_provider, :compressor, :port,
|
24
24
|
:connect_timeout, :ssl, :connections_per_local_node,
|
25
25
|
:connections_per_remote_node, :heartbeat_interval,
|
26
|
-
:idle_timeout
|
26
|
+
:idle_timeout, :schema_refresh_delay, :schema_refresh_timeout
|
27
27
|
attr_accessor :protocol_version
|
28
28
|
|
29
|
-
def initialize(protocol_version, credentials, auth_provider, compressor, port, connect_timeout, ssl, connections_per_local_node, connections_per_remote_node, heartbeat_interval, idle_timeout)
|
30
|
-
@protocol_version
|
31
|
-
@credentials
|
32
|
-
@auth_provider
|
33
|
-
@compressor
|
34
|
-
@port
|
35
|
-
@connect_timeout
|
36
|
-
@ssl
|
37
|
-
@heartbeat_interval
|
38
|
-
@idle_timeout
|
29
|
+
def initialize(protocol_version, credentials, auth_provider, compressor, port, connect_timeout, ssl, connections_per_local_node, connections_per_remote_node, heartbeat_interval, idle_timeout, synchronize_schema, schema_refresh_delay, schema_refresh_timeout)
|
30
|
+
@protocol_version = protocol_version
|
31
|
+
@credentials = credentials
|
32
|
+
@auth_provider = auth_provider
|
33
|
+
@compressor = compressor
|
34
|
+
@port = port
|
35
|
+
@connect_timeout = connect_timeout
|
36
|
+
@ssl = ssl
|
37
|
+
@heartbeat_interval = heartbeat_interval
|
38
|
+
@idle_timeout = idle_timeout
|
39
|
+
@synchronize_schema = synchronize_schema
|
40
|
+
@schema_refresh_delay = schema_refresh_delay
|
41
|
+
@schema_refresh_timeout = schema_refresh_timeout
|
39
42
|
|
40
43
|
@connections_per_local_node = connections_per_local_node
|
41
44
|
@connections_per_remote_node = connections_per_remote_node
|
42
45
|
end
|
46
|
+
|
47
|
+
def synchronize_schema?
|
48
|
+
@synchronize_schema
|
49
|
+
end
|
50
|
+
|
51
|
+
def compression
|
52
|
+
@compressor && @compressor.algorithm
|
53
|
+
end
|
54
|
+
|
55
|
+
def create_authenticator(authentication_class)
|
56
|
+
@auth_provider && @auth_provider.create_authenticator(authentication_class)
|
57
|
+
end
|
43
58
|
end
|
44
59
|
end
|
45
60
|
end
|
@@ -130,6 +130,9 @@ module Cassandra
|
|
130
130
|
|
131
131
|
return self unless keyspace
|
132
132
|
|
133
|
+
columns = columns.each_with_object(::Hash.new) do |row, index|
|
134
|
+
index[row['column_name']] = row
|
135
|
+
end
|
133
136
|
table = create_table(table, columns, host.release_version)
|
134
137
|
keyspace = keyspace.update_table(table)
|
135
138
|
|
@@ -139,7 +142,25 @@ module Cassandra
|
|
139
142
|
@keyspaces = keyspaces
|
140
143
|
end
|
141
144
|
|
142
|
-
|
145
|
+
keyspace_changed(keyspace)
|
146
|
+
|
147
|
+
self
|
148
|
+
end
|
149
|
+
|
150
|
+
def delete_table(keyspace_name, table_name)
|
151
|
+
keyspace = @keyspaces[keyspace_name]
|
152
|
+
|
153
|
+
return self unless keyspace
|
154
|
+
|
155
|
+
keyspace = keyspace.delete_table(table_name)
|
156
|
+
|
157
|
+
synchronize do
|
158
|
+
keyspaces = @keyspaces.dup
|
159
|
+
keyspaces[keyspace_name] = keyspace
|
160
|
+
@keyspaces = keyspaces
|
161
|
+
end
|
162
|
+
|
163
|
+
keyspace_changed(keyspace)
|
143
164
|
|
144
165
|
self
|
145
166
|
end
|
data/lib/cassandra/column.rb
CHANGED
@@ -78,6 +78,11 @@ module Cassandra
|
|
78
78
|
cql
|
79
79
|
end
|
80
80
|
|
81
|
+
# @return [String] a CLI-friendly column representation
|
82
|
+
def inspect
|
83
|
+
"#<#{self.class.name}:0x#{self.object_id.to_s(16)} @name=#{@name}>"
|
84
|
+
end
|
85
|
+
|
81
86
|
# @return [Boolean] whether this column is equal to the other
|
82
87
|
def eql?(other)
|
83
88
|
other.is_a?(Column) &&
|
data/lib/cassandra/driver.rb
CHANGED
@@ -20,7 +20,7 @@ module Cassandra
|
|
20
20
|
# @private
|
21
21
|
class Driver
|
22
22
|
def self.let(name, &block)
|
23
|
-
define_method(name) { @instances[name]
|
23
|
+
define_method(name) { @instances.has_key?(name) ? @instances[name] : @instances[name] = instance_eval(&block) }
|
24
24
|
define_method(:"#{name}=") { |object| @instances[name] = object }
|
25
25
|
end
|
26
26
|
|
@@ -42,7 +42,9 @@ module Cassandra
|
|
42
42
|
no_replication_strategy
|
43
43
|
)
|
44
44
|
}
|
45
|
-
|
45
|
+
|
46
|
+
let(:executor) { Executors::ThreadPool.new(thread_pool_size) }
|
47
|
+
let(:futures_factory) { Future::Factory.new(executor) }
|
46
48
|
|
47
49
|
let(:schema_type_parser) { Cluster::Schema::TypeParser.new }
|
48
50
|
|
@@ -54,11 +56,11 @@ module Cassandra
|
|
54
56
|
let(:ordered_partitioner) { Cluster::Schema::Partitioners::Ordered.new }
|
55
57
|
let(:random_partitioner) { Cluster::Schema::Partitioners::Random.new }
|
56
58
|
|
57
|
-
let(:connector) { Cluster::Connector.new(logger, io_reactor, cluster_registry, connection_options) }
|
59
|
+
let(:connector) { Cluster::Connector.new(logger, io_reactor, cluster_registry, connection_options, execution_options) }
|
58
60
|
|
59
|
-
let(:control_connection) { Cluster::ControlConnection.new(logger, io_reactor, cluster_registry, cluster_schema, cluster_metadata, load_balancing_policy, reconnection_policy, address_resolution_policy, connector) }
|
61
|
+
let(:control_connection) { Cluster::ControlConnection.new(logger, io_reactor, cluster_registry, cluster_schema, cluster_metadata, load_balancing_policy, reconnection_policy, address_resolution_policy, connector, connection_options) }
|
60
62
|
|
61
|
-
let(:cluster) { Cluster.new(logger, io_reactor, control_connection, cluster_registry, cluster_schema, cluster_metadata, execution_options, connection_options, load_balancing_policy, reconnection_policy, retry_policy, address_resolution_policy, connector, futures_factory) }
|
63
|
+
let(:cluster) { Cluster.new(logger, io_reactor, executor, control_connection, cluster_registry, cluster_schema, cluster_metadata, execution_options, connection_options, load_balancing_policy, reconnection_policy, retry_policy, address_resolution_policy, connector, futures_factory) }
|
62
64
|
|
63
65
|
let(:execution_options) do
|
64
66
|
Execution::Options.new({
|
@@ -69,27 +71,49 @@ module Cassandra
|
|
69
71
|
})
|
70
72
|
end
|
71
73
|
|
72
|
-
let(:connection_options)
|
74
|
+
let(:connection_options) do
|
75
|
+
Cluster::Options.new(
|
76
|
+
protocol_version,
|
77
|
+
credentials,
|
78
|
+
auth_provider,
|
79
|
+
compressor,
|
80
|
+
port,
|
81
|
+
connect_timeout,
|
82
|
+
ssl,
|
83
|
+
connections_per_local_node,
|
84
|
+
connections_per_remote_node,
|
85
|
+
heartbeat_interval,
|
86
|
+
idle_timeout,
|
87
|
+
synchronize_schema,
|
88
|
+
schema_refresh_delay,
|
89
|
+
schema_refresh_timeout
|
90
|
+
)
|
91
|
+
end
|
73
92
|
|
74
93
|
let(:port) { 9042 }
|
75
94
|
let(:protocol_version) { 2 }
|
76
95
|
let(:connect_timeout) { 10 }
|
77
96
|
let(:ssl) { false }
|
78
|
-
let(:logger) {
|
97
|
+
let(:logger) { NullLogger.new }
|
79
98
|
let(:compressor) { nil }
|
80
99
|
let(:credentials) { nil }
|
81
100
|
let(:auth_provider) { nil }
|
82
101
|
let(:datacenter) { nil }
|
83
|
-
let(:load_balancing_policy) { LoadBalancing::Policies::TokenAware.new(LoadBalancing::Policies::DCAwareRoundRobin.new(datacenter, 0)) }
|
102
|
+
let(:load_balancing_policy) { LoadBalancing::Policies::TokenAware.new(LoadBalancing::Policies::DCAwareRoundRobin.new(datacenter, 0), shuffle_replicas) }
|
84
103
|
let(:reconnection_policy) { Reconnection::Policies::Exponential.new(0.5, 30, 2) }
|
85
104
|
let(:retry_policy) { Retry::Policies::Default.new }
|
86
105
|
let(:address_resolution_policy) { AddressResolution::Policies::None.new }
|
87
106
|
let(:consistency) { :one }
|
88
107
|
let(:trace) { false }
|
89
|
-
let(:page_size) {
|
108
|
+
let(:page_size) { 10000 }
|
90
109
|
let(:heartbeat_interval) { 30 }
|
91
110
|
let(:idle_timeout) { 60 }
|
92
111
|
let(:timeout) { 10 }
|
112
|
+
let(:synchronize_schema) { true }
|
113
|
+
let(:schema_refresh_delay) { 1 }
|
114
|
+
let(:schema_refresh_timeout) { 10 }
|
115
|
+
let(:thread_pool_size) { 4 }
|
116
|
+
let(:shuffle_replicas) { true }
|
93
117
|
|
94
118
|
let(:connections_per_local_node) { 2 }
|
95
119
|
let(:connections_per_remote_node) { 1 }
|
@@ -97,8 +121,7 @@ module Cassandra
|
|
97
121
|
let(:listeners) { [] }
|
98
122
|
|
99
123
|
def initialize(defaults = {})
|
100
|
-
@
|
101
|
-
@instances = {}
|
124
|
+
@instances = defaults
|
102
125
|
end
|
103
126
|
|
104
127
|
def connect(addresses)
|
@@ -113,7 +136,18 @@ module Cassandra
|
|
113
136
|
addresses.each {|address| cluster_registry.host_found(address)}
|
114
137
|
|
115
138
|
logger.info('Establishing control connection')
|
116
|
-
|
139
|
+
|
140
|
+
promise = futures_factory.promise
|
141
|
+
|
142
|
+
control_connection.connect_async.on_complete do |f|
|
143
|
+
if f.resolved?
|
144
|
+
promise.fulfill(cluster)
|
145
|
+
else
|
146
|
+
f.on_failure {|e| promise.break(e)}
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
promise.future
|
117
151
|
end
|
118
152
|
end
|
119
153
|
end
|
data/lib/cassandra/errors.rb
CHANGED
@@ -49,28 +49,28 @@ module Cassandra
|
|
49
49
|
end
|
50
50
|
|
51
51
|
# Mixed into all internal driver errors.
|
52
|
-
|
52
|
+
class InternalError < ::RuntimeError
|
53
53
|
include Error, HostError
|
54
54
|
end
|
55
55
|
|
56
56
|
# Raised when data decoding fails.
|
57
57
|
class DecodingError < ::RuntimeError
|
58
|
-
include
|
58
|
+
include Error, HostError
|
59
59
|
end
|
60
60
|
|
61
61
|
# Raised when data encoding fails.
|
62
62
|
class EncodingError < ::RuntimeError
|
63
|
-
include
|
63
|
+
include Error, HostError
|
64
64
|
end
|
65
65
|
|
66
66
|
# Raised when a connection level error occured.
|
67
67
|
class IOError < ::IOError
|
68
|
-
include
|
68
|
+
include Error, HostError
|
69
69
|
end
|
70
70
|
|
71
71
|
# Raised when a timeout has occured.
|
72
72
|
class TimeoutError < ::Timeout::Error
|
73
|
-
include
|
73
|
+
include Error, HostError
|
74
74
|
end
|
75
75
|
|
76
76
|
# Mixed into all request execution errors.
|
@@ -31,6 +31,20 @@ module Cassandra
|
|
31
31
|
# @return [Numeric] request timeout interval
|
32
32
|
attr_reader :timeout
|
33
33
|
|
34
|
+
# @return [String] paging state
|
35
|
+
#
|
36
|
+
# @note Although this feature exists to allow web applications to store
|
37
|
+
# paging state in an [HTTP cookie](http://en.wikipedia.org/wiki/HTTP_cookie), **it is not safe to
|
38
|
+
# expose without encrypting or otherwise securing it**. Paging state
|
39
|
+
# contains information internal to the Apache Cassandra cluster, such as
|
40
|
+
# partition key and data. Additionally, if a paging state is sent with CQL
|
41
|
+
# statement, different from the original, the behavior of Cassandra is
|
42
|
+
# undefined and will likely cause a server process of the coordinator of
|
43
|
+
# such request to abort.
|
44
|
+
#
|
45
|
+
# @see Cassandra::Result#paging_state
|
46
|
+
attr_reader :paging_state
|
47
|
+
|
34
48
|
# @private
|
35
49
|
def initialize(options)
|
36
50
|
consistency = options[:consistency]
|
@@ -38,21 +52,35 @@ module Cassandra
|
|
38
52
|
trace = options[:trace]
|
39
53
|
timeout = options[:timeout]
|
40
54
|
serial_consistency = options[:serial_consistency]
|
55
|
+
paging_state = options[:paging_state]
|
56
|
+
|
57
|
+
Util.assert_one_of(CONSISTENCIES, consistency) { ":consistency must be one of #{CONSISTENCIES.inspect}, #{consistency.inspect} given" }
|
41
58
|
|
42
|
-
|
43
|
-
|
59
|
+
unless serial_consistency.nil?
|
60
|
+
Util.assert_one_of(SERIAL_CONSISTENCIES, serial_consistency) { ":serial_consistency must be one of #{SERIAL_CONSISTENCIES.inspect}, #{serial_consistency.inspect} given" }
|
61
|
+
end
|
44
62
|
|
45
|
-
|
46
|
-
|
63
|
+
unless page_size.nil?
|
64
|
+
page_size = Integer(page_size)
|
65
|
+
Util.assert(page_size > 0) { ":page_size must be a positive integer, #{page_size.inspect} given" }
|
66
|
+
end
|
47
67
|
|
48
|
-
|
49
|
-
|
68
|
+
unless timeout.nil?
|
69
|
+
Util.assert_instance_of(::Numeric, timeout) { ":timeout must be a number of seconds, #{timeout} given" }
|
70
|
+
Util.assert(timeout > 0) { ":timeout must be greater than 0, #{timeout} given" }
|
71
|
+
end
|
72
|
+
|
73
|
+
unless paging_state.nil?
|
74
|
+
paging_state = String(paging_state)
|
75
|
+
Util.assert_not_empty(paging_state) { ":paging_state must not be empty" }
|
76
|
+
end
|
50
77
|
|
51
78
|
@consistency = consistency
|
52
79
|
@page_size = page_size
|
53
80
|
@trace = !!trace
|
54
81
|
@timeout = timeout
|
55
82
|
@serial_consistency = serial_consistency
|
83
|
+
@paging_state = paging_state
|
56
84
|
end
|
57
85
|
|
58
86
|
# @return [Boolean] whether request tracing was enabled
|
@@ -61,8 +89,14 @@ module Cassandra
|
|
61
89
|
end
|
62
90
|
|
63
91
|
# @private
|
64
|
-
def override(options)
|
65
|
-
|
92
|
+
def override(*options)
|
93
|
+
merged = options.unshift(to_h).inject do |base, opts|
|
94
|
+
next base unless opts
|
95
|
+
Util.assert_instance_of(::Hash, opts) { "options must be a Hash, #{options.inspect} given" }
|
96
|
+
base.merge!(opts)
|
97
|
+
end
|
98
|
+
|
99
|
+
Options.new(merged)
|
66
100
|
end
|
67
101
|
|
68
102
|
# @private
|
@@ -108,16 +108,16 @@ module Cassandra
|
|
108
108
|
private
|
109
109
|
|
110
110
|
# @private
|
111
|
-
SELECT_SESSION = "SELECT * FROM system_traces.sessions WHERE session_id =
|
111
|
+
SELECT_SESSION = "SELECT * FROM system_traces.sessions WHERE session_id = %s"
|
112
112
|
# @private
|
113
|
-
SELECT_EVENTS = "SELECT * FROM system_traces.events WHERE session_id =
|
113
|
+
SELECT_EVENTS = "SELECT * FROM system_traces.events WHERE session_id = %s"
|
114
114
|
|
115
115
|
# @private
|
116
116
|
def load
|
117
117
|
synchronize do
|
118
118
|
return if @loaded
|
119
119
|
|
120
|
-
data = @client.query(Statements::Simple.new(SELECT_SESSION
|
120
|
+
data = @client.query(Statements::Simple.new(SELECT_SESSION % @id), VOID_OPTIONS).get.first
|
121
121
|
raise ::RuntimeError, "unable to load trace #{@id}" if data.nil?
|
122
122
|
|
123
123
|
@coordinator = data['coordinator']
|
@@ -138,7 +138,7 @@ module Cassandra
|
|
138
138
|
|
139
139
|
@events = []
|
140
140
|
|
141
|
-
@client.query(Statements::Simple.new(SELECT_EVENTS
|
141
|
+
@client.query(Statements::Simple.new(SELECT_EVENTS % @id), VOID_OPTIONS).get.each do |row|
|
142
142
|
@events << Event.new(row['event_id'], row['activity'], row['source'], row['source_elapsed'], row['thread'])
|
143
143
|
end
|
144
144
|
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
#--
|
4
|
+
# Copyright 2013-2014 DataStax, Inc.
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#++
|
18
|
+
|
19
|
+
module Cassandra
|
20
|
+
# @private
|
21
|
+
module Executors
|
22
|
+
class ThreadPool
|
23
|
+
# @private
|
24
|
+
class Task
|
25
|
+
def initialize(*args, &block)
|
26
|
+
@args = args
|
27
|
+
@block = block
|
28
|
+
end
|
29
|
+
|
30
|
+
def run
|
31
|
+
@block.call(*@args)
|
32
|
+
rescue ::Exception
|
33
|
+
ensure
|
34
|
+
@args = @block = nil
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
include MonitorMixin
|
39
|
+
|
40
|
+
def initialize(size)
|
41
|
+
mon_initialize
|
42
|
+
|
43
|
+
@cond = new_cond
|
44
|
+
@tasks = ::Array.new
|
45
|
+
@waiting = 0
|
46
|
+
@pool = ::Array.new(size, &method(:spawn_thread))
|
47
|
+
@term = false
|
48
|
+
end
|
49
|
+
|
50
|
+
def execute(*args, &block)
|
51
|
+
synchronize do
|
52
|
+
@tasks << Task.new(*args, &block)
|
53
|
+
@cond.signal if @waiting > 0
|
54
|
+
end
|
55
|
+
|
56
|
+
nil
|
57
|
+
end
|
58
|
+
|
59
|
+
def shutdown
|
60
|
+
execute do
|
61
|
+
synchronize do
|
62
|
+
@term = true
|
63
|
+
@cond.broadcast if @waiting > 0
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
nil
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def spawn_thread(i)
|
73
|
+
Thread.new(&method(:run))
|
74
|
+
end
|
75
|
+
|
76
|
+
def run
|
77
|
+
Thread.current.abort_on_exception = true
|
78
|
+
|
79
|
+
loop do
|
80
|
+
tasks = nil
|
81
|
+
|
82
|
+
synchronize do
|
83
|
+
@waiting += 1
|
84
|
+
@cond.wait while !@term && @tasks.empty?
|
85
|
+
@waiting -= 1
|
86
|
+
|
87
|
+
return if @tasks.empty?
|
88
|
+
|
89
|
+
tasks = @tasks
|
90
|
+
@tasks = ::Array.new
|
91
|
+
end
|
92
|
+
|
93
|
+
tasks.each(&:run).clear
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
class SameThread
|
99
|
+
def execute(*args, &block)
|
100
|
+
yield(*args)
|
101
|
+
nil
|
102
|
+
rescue ::Exception
|
103
|
+
nil
|
104
|
+
end
|
105
|
+
|
106
|
+
def shutdown
|
107
|
+
nil
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|