cassandra-driver 1.0.0.beta.3-java → 1.0.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 +51 -14
- data/lib/cassandra.rb +164 -78
- data/lib/cassandra/address_resolution.rb +36 -0
- data/lib/cassandra/address_resolution/policies.rb +2 -0
- data/lib/cassandra/address_resolution/policies/ec2_multi_region.rb +56 -0
- data/lib/cassandra/address_resolution/policies/none.rb +35 -0
- data/lib/cassandra/auth.rb +1 -1
- data/lib/cassandra/auth/providers/password.rb +1 -1
- data/lib/cassandra/cluster.rb +18 -5
- data/lib/cassandra/cluster/client.rb +175 -101
- data/lib/cassandra/{client/connection_manager.rb → cluster/connection_pool.rb} +5 -5
- data/lib/cassandra/cluster/connector.rb +142 -56
- data/lib/cassandra/cluster/control_connection.rb +385 -134
- data/lib/cassandra/{client/null_logger.rb → cluster/failed_connection.rb} +12 -14
- data/lib/cassandra/cluster/options.rb +13 -2
- data/lib/cassandra/cluster/registry.rb +19 -9
- data/lib/cassandra/column.rb +5 -0
- data/lib/cassandra/compression.rb +1 -1
- data/lib/cassandra/compression/compressors/lz4.rb +1 -1
- data/lib/cassandra/compression/compressors/snappy.rb +1 -1
- data/lib/cassandra/driver.rb +29 -21
- data/lib/cassandra/errors.rb +325 -35
- data/lib/cassandra/execution/options.rb +13 -6
- data/lib/cassandra/execution/trace.rb +4 -4
- data/lib/cassandra/future.rb +7 -3
- data/lib/cassandra/keyspace.rb +5 -0
- data/lib/cassandra/load_balancing/policies/dc_aware_round_robin.rb +13 -4
- data/lib/cassandra/load_balancing/policies/token_aware.rb +2 -4
- data/lib/cassandra/load_balancing/policies/white_list.rb +3 -6
- data/lib/cassandra/null_logger.rb +35 -0
- data/lib/cassandra/protocol.rb +0 -16
- data/lib/cassandra/protocol/cql_byte_buffer.rb +18 -18
- data/lib/cassandra/protocol/cql_protocol_handler.rb +78 -8
- data/lib/cassandra/protocol/frame_decoder.rb +2 -2
- data/lib/cassandra/protocol/frame_encoder.rb +1 -1
- data/lib/cassandra/protocol/requests/query_request.rb +1 -11
- data/lib/cassandra/protocol/response.rb +1 -1
- data/lib/cassandra/protocol/responses/detailed_error_response.rb +16 -1
- data/lib/cassandra/protocol/responses/error_response.rb +17 -0
- data/lib/cassandra/protocol/responses/event_response.rb +1 -1
- data/lib/cassandra/protocol/responses/raw_rows_result_response.rb +1 -1
- data/lib/cassandra/protocol/responses/result_response.rb +1 -1
- data/lib/cassandra/protocol/responses/rows_result_response.rb +1 -1
- data/lib/cassandra/protocol/type_converter.rb +4 -3
- data/lib/cassandra/reconnection.rb +1 -1
- data/lib/cassandra/result.rb +4 -6
- data/lib/cassandra/retry.rb +3 -5
- data/lib/cassandra/session.rb +14 -5
- data/lib/cassandra/statements/prepared.rb +5 -1
- data/lib/cassandra/table.rb +6 -1
- data/lib/cassandra/time_uuid.rb +21 -83
- data/lib/cassandra/util.rb +131 -1
- data/lib/cassandra/uuid.rb +6 -4
- data/lib/cassandra/uuid/generator.rb +207 -0
- data/lib/cassandra/version.rb +1 -1
- data/lib/cassandra_murmur3.jar +0 -0
- metadata +43 -49
- 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 -277
- 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 -71
- data/lib/cassandra/client/result_metadata.rb +0 -48
- data/lib/cassandra/client/void_result.rb +0 -78
@@ -47,7 +47,7 @@ module Cassandra
|
|
47
47
|
|
48
48
|
def actual_decode(buffer, fields, size)
|
49
49
|
if (fields >> 24) & 0x80 == 0
|
50
|
-
raise
|
50
|
+
raise Errors::DecodingError, 'Request frames are not supported'
|
51
51
|
end
|
52
52
|
protocol_version = (fields >> 24) & 0x7f
|
53
53
|
compression = (fields >> 16) & 0x01
|
@@ -78,7 +78,7 @@ module Cassandra
|
|
78
78
|
compressed_body = buffer.read(size)
|
79
79
|
CqlByteBuffer.new(@compressor.decompress(compressed_body))
|
80
80
|
else
|
81
|
-
raise
|
81
|
+
raise Errors::DecodingError, 'Compressed frame received, but no compressor configured'
|
82
82
|
end
|
83
83
|
end
|
84
84
|
|
@@ -26,7 +26,7 @@ module Cassandra
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def encode_frame(request, stream_id=0, buffer=nil)
|
29
|
-
raise
|
29
|
+
raise EncodingError, 'The stream ID must be between 0 and 127' unless 0 <= stream_id && stream_id < 128
|
30
30
|
buffer ||= CqlByteBuffer.new
|
31
31
|
flags = request.trace? ? 2 : 0
|
32
32
|
body = request.write(@protocol_version, CqlByteBuffer.new)
|
@@ -39,11 +39,7 @@ module Cassandra
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def write(protocol_version, buffer)
|
42
|
-
|
43
|
-
buffer.append_long_string(@cql)
|
44
|
-
else
|
45
|
-
buffer.append_long_string(serialized_cql)
|
46
|
-
end
|
42
|
+
buffer.append_long_string(@cql)
|
47
43
|
buffer.append_consistency(@consistency)
|
48
44
|
if protocol_version > 1
|
49
45
|
flags = 0
|
@@ -108,12 +104,6 @@ module Cassandra
|
|
108
104
|
|
109
105
|
private
|
110
106
|
|
111
|
-
def serialized_cql
|
112
|
-
return @cql if @values.nil? || @values.empty?
|
113
|
-
i = -1
|
114
|
-
@cql.gsub('?') { Util.encode(@values[i += 1]) }
|
115
|
-
end
|
116
|
-
|
117
107
|
def self.guess_type(value)
|
118
108
|
type = TYPE_GUESSES[value.class]
|
119
109
|
if type == :map
|
@@ -24,7 +24,7 @@ module Cassandra
|
|
24
24
|
if response_class
|
25
25
|
response_class.decode(protocol_version, buffer, length, trace_id)
|
26
26
|
else
|
27
|
-
raise
|
27
|
+
raise Errors::DecodingError, "Unsupported opcode #{opcode.inspect}"
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
@@ -37,7 +37,10 @@ module Cassandra
|
|
37
37
|
details[:cl] = buffer.read_consistency
|
38
38
|
details[:received] = buffer.read_int
|
39
39
|
details[:blockfor] = buffer.read_int
|
40
|
-
|
40
|
+
write_type = buffer.read_string
|
41
|
+
write_type.downcase!
|
42
|
+
|
43
|
+
details[:write_type] = write_type.to_sym
|
41
44
|
when 0x1200 # read_timeout
|
42
45
|
details[:cl] = buffer.read_consistency
|
43
46
|
details[:received] = buffer.read_int
|
@@ -52,6 +55,18 @@ module Cassandra
|
|
52
55
|
new(code, message, details)
|
53
56
|
end
|
54
57
|
|
58
|
+
def to_error(statement = nil)
|
59
|
+
case code
|
60
|
+
when 0x1000 then Errors::UnavailableError.new(@message, statement, @details[:cl], @details[:required], @details[:alive])
|
61
|
+
when 0x1100 then Errors::WriteTimeoutError.new(@message, statement, @details[:write_type], @details[:cl], @details[:blockfor], @details[:received])
|
62
|
+
when 0x1200 then Errors::ReadTimeoutError.new(@message, statement, @details[:data_present], @details[:cl], @details[:blockfor], @details[:received])
|
63
|
+
when 0x2400 then Errors::AlreadyExistsError.new(@message, statement, @details[:ks], @details[:table])
|
64
|
+
when 0x2500 then Errors::UnpreparedError.new(@message, statement, @details[:id])
|
65
|
+
else
|
66
|
+
super
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
55
70
|
def to_s
|
56
71
|
"#{super} #{@details}"
|
57
72
|
end
|
@@ -42,6 +42,23 @@ module Cassandra
|
|
42
42
|
%(ERROR 0x#{hex_code} "#@message")
|
43
43
|
end
|
44
44
|
|
45
|
+
def to_error(statement = nil)
|
46
|
+
case @code
|
47
|
+
when 0x0000 then Errors::ServerError.new(@message)
|
48
|
+
when 0x000A then Errors::ProtocolError.new(@message)
|
49
|
+
when 0x0100 then Errors::AuthenticationError.new(@message)
|
50
|
+
when 0x1001 then Errors::OverloadedError.new(@message, statement)
|
51
|
+
when 0x1002 then Errors::IsBootstrappingError.new(@message, statement)
|
52
|
+
when 0x1003 then Errors::TruncateError.new(@message, statement)
|
53
|
+
when 0x2000 then Errors::SyntaxError.new(@message, statement)
|
54
|
+
when 0x2100 then Errors::UnauthorizedError.new(@message, statement)
|
55
|
+
when 0x2200 then Errors::InvalidError.new(@message, statement)
|
56
|
+
when 0x2300 then Errors::ConfigurationError.new(@message, statement)
|
57
|
+
else
|
58
|
+
Errors::ServerError.new(@message)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
45
62
|
private
|
46
63
|
|
47
64
|
RESPONSE_TYPES[0x00] = self
|
@@ -22,7 +22,7 @@ module Cassandra
|
|
22
22
|
def self.decode(protocol_version, buffer, length, trace_id=nil)
|
23
23
|
type = buffer.read_string
|
24
24
|
impl = EVENT_TYPES[type]
|
25
|
-
raise
|
25
|
+
raise Errors::DecodingError, %(Unsupported event type: "#{type}") unless impl
|
26
26
|
new_length = length - 4 - type.bytesize
|
27
27
|
impl.decode(protocol_version, buffer, new_length, trace_id)
|
28
28
|
end
|
@@ -28,7 +28,7 @@ module Cassandra
|
|
28
28
|
def self.decode(protocol_version, buffer, length, trace_id=nil)
|
29
29
|
kind = buffer.read_int
|
30
30
|
impl = RESULT_TYPES[kind]
|
31
|
-
raise
|
31
|
+
raise Errors::DecodingError, %(Unsupported result kind: #{kind}) unless impl
|
32
32
|
impl.decode(protocol_version, buffer, length - 4, trace_id)
|
33
33
|
end
|
34
34
|
|
@@ -46,7 +46,7 @@ module Cassandra
|
|
46
46
|
case type
|
47
47
|
when Array
|
48
48
|
unless value.nil? || value.is_a?(Enumerable)
|
49
|
-
raise
|
49
|
+
raise EncodingError, 'Value for collection must be enumerable'
|
50
50
|
end
|
51
51
|
case type.first
|
52
52
|
when :list, :set
|
@@ -75,12 +75,12 @@ module Cassandra
|
|
75
75
|
nil_to_bytes(buffer, size_bytes)
|
76
76
|
end
|
77
77
|
else
|
78
|
-
raise
|
78
|
+
raise EncodingError, %(Unsupported column collection type: #{type.first})
|
79
79
|
end
|
80
80
|
else
|
81
81
|
converter = @to_bytes_converters[type]
|
82
82
|
unless converter
|
83
|
-
raise
|
83
|
+
raise EncodingError, %(Unsupported column type: #{type})
|
84
84
|
end
|
85
85
|
converter.call(buffer, value, size_bytes)
|
86
86
|
end
|
@@ -140,6 +140,7 @@ module Cassandra
|
|
140
140
|
size = buffer.read_signed_int
|
141
141
|
return nil if size & 0x80000000 == 0x80000000
|
142
142
|
end
|
143
|
+
return nil if size.zero?
|
143
144
|
size
|
144
145
|
end
|
145
146
|
|
@@ -30,7 +30,7 @@ module Cassandra
|
|
30
30
|
|
31
31
|
# A reconnection policy
|
32
32
|
# @abstract Actual reconnection policies supplied as `:reconnection_policy`
|
33
|
-
# option to {Cassandra.
|
33
|
+
# option to {Cassandra.cluster} don't need to inherit this class, only
|
34
34
|
# implement its methods. This class exists for documentation purposes
|
35
35
|
# only.
|
36
36
|
class Policy
|
data/lib/cassandra/result.rb
CHANGED
@@ -180,10 +180,9 @@ module Cassandra
|
|
180
180
|
# Returns true when there are no more pages to load.
|
181
181
|
#
|
182
182
|
# This is only relevant when you have requested paging of the results with
|
183
|
-
# the `:page_size` option to {Cassandra::
|
184
|
-
# {Cassandra::Client::PreparedStatement#execute}.
|
183
|
+
# the `:page_size` option to {Cassandra::Session#execute}.
|
185
184
|
#
|
186
|
-
# @see Cassandra::
|
185
|
+
# @see Cassandra::Session#execute
|
187
186
|
def last_page?
|
188
187
|
true
|
189
188
|
end
|
@@ -191,10 +190,9 @@ module Cassandra
|
|
191
190
|
# Returns the next page or nil when there is no next page.
|
192
191
|
#
|
193
192
|
# This is only relevant when you have requested paging of the results with
|
194
|
-
# the `:page_size` option to {Cassandra::
|
195
|
-
# {Cassandra::Client::PreparedStatement#execute}.
|
193
|
+
# the `:page_size` option to {Cassandra::Session#execute_async}.
|
196
194
|
#
|
197
|
-
# @see Cassandra::
|
195
|
+
# @see Cassandra::Session#execute_async
|
198
196
|
def next_page_async(options = nil)
|
199
197
|
@futures.value(nil)
|
200
198
|
end
|
data/lib/cassandra/retry.rb
CHANGED
@@ -19,7 +19,7 @@
|
|
19
19
|
module Cassandra
|
20
20
|
module Retry
|
21
21
|
# @abstract Actual retry policies supplied as `:retry_policy` option to
|
22
|
-
# {Cassandra.
|
22
|
+
# {Cassandra.cluster} don't need to inherit this class, only implement
|
23
23
|
# its methods. This class exists for documentation purposes only.
|
24
24
|
module Policy
|
25
25
|
# Decides wether to retry a read and at what consistency level.
|
@@ -51,8 +51,7 @@ module Cassandra
|
|
51
51
|
# @param statement [Cassandra::Statement] the original statement that timed out
|
52
52
|
# @param consistency [Symbol] the original consistency level for the
|
53
53
|
# request, one of {Cassandra::CONSISTENCIES}
|
54
|
-
# @param type [Symbol] One of
|
55
|
-
# `:counter` or `:batch_log`
|
54
|
+
# @param type [Symbol] One of {Cassandra::WRITE_TYPES}
|
56
55
|
# @param required [Integer] the number of acks required to achieve
|
57
56
|
# requested consistency level
|
58
57
|
# @param received [Integer] the number of acks received by the time the
|
@@ -75,8 +74,7 @@ module Cassandra
|
|
75
74
|
# request, one of {Cassandra::CONSISTENCIES}
|
76
75
|
# @param required [Integer] the number of replicas required to achieve
|
77
76
|
# requested consistency level
|
78
|
-
# @param alive [Integer] the number of replicas
|
79
|
-
# query timed out
|
77
|
+
# @param alive [Integer] the number of replicas available for the request
|
80
78
|
# @param retries [Integer] the number of retries already performed
|
81
79
|
#
|
82
80
|
# @return [Cassandra::Policies::Retry::Decision] a retry decision
|
data/lib/cassandra/session.rb
CHANGED
@@ -54,14 +54,20 @@ module Cassandra
|
|
54
54
|
# relevant for conditional updates and specifies a serial consistency to
|
55
55
|
# be used, one of {Cassandra::SERIAL_CONSISTENCIES}
|
56
56
|
#
|
57
|
-
# @see Cassandra.
|
58
|
-
#
|
57
|
+
# @see Cassandra.cluster Options that can be specified on the cluster-level
|
58
|
+
# and their default values.
|
59
59
|
#
|
60
60
|
# @note Last argument will be treated as `options` if it is a {Hash}.
|
61
61
|
# Therefore, make sure to pass empty `options` when executing a statement
|
62
62
|
# with the last parameter required to be a map datatype.
|
63
63
|
#
|
64
|
+
# @note Positional arguments are only supported on Apache Cassandra 2.0 and
|
65
|
+
# above.
|
66
|
+
#
|
64
67
|
# @return [Cassandra::Future<Cassandra::Result>]
|
68
|
+
#
|
69
|
+
# @see Cassandra::Session#execute A list of errors this future can be
|
70
|
+
# resolved with
|
65
71
|
def execute_async(statement, *args)
|
66
72
|
if args.last.is_a?(::Hash)
|
67
73
|
options = @options.override(args.pop)
|
@@ -91,8 +97,11 @@ module Cassandra
|
|
91
97
|
# @see Cassandra::Future#get
|
92
98
|
#
|
93
99
|
# @return [Cassandra::Result] query result
|
94
|
-
# @raise [Cassandra::Errors::NoHostsAvailable] if
|
95
|
-
# @raise [Cassandra::Errors::
|
100
|
+
# @raise [Cassandra::Errors::NoHostsAvailable] if all hosts fail
|
101
|
+
# @raise [Cassandra::Errors::ExecutionError] if Cassandra fails to execute
|
102
|
+
# @raise [Cassandra::Errors::ValidationError] if Cassandra fails to validate
|
103
|
+
# @raise [Cassandra::Errors::TimeoutError] if request has not completed
|
104
|
+
# within the `:timeout` given
|
96
105
|
def execute(*args)
|
97
106
|
execute_async(*args).get
|
98
107
|
end
|
@@ -131,7 +140,7 @@ module Cassandra
|
|
131
140
|
#
|
132
141
|
# @return [Cassandra::Statements::Prepared] prepared statement
|
133
142
|
# @raise [Cassandra::Errors::NoHostsAvailable] if none of the hosts can be reached
|
134
|
-
# @raise [Cassandra::Errors::
|
143
|
+
# @raise [Cassandra::Errors::ExecutionError] if Cassandra returns an error response
|
135
144
|
def prepare(*args)
|
136
145
|
prepare_async(*args).get
|
137
146
|
end
|
@@ -50,7 +50,11 @@ module Cassandra
|
|
50
50
|
# original cql passed to {Cassandra::Session#prepare}
|
51
51
|
# @return [Cassandra::Statements::Bound] bound statement
|
52
52
|
def bind(*args)
|
53
|
-
|
53
|
+
Util.assert_equal(@params_metadata.size, args.size) { "expecting exactly #{@params_metadata.size} bind parameters, #{args.size} given" }
|
54
|
+
|
55
|
+
@params_metadata.each_with_index do |metadata, i|
|
56
|
+
Util.assert_type(metadata[3], args[i]) { "argument for #{metadata[2].inspect} must be #{metadata[3].inspect}, #{args[i]} given" }
|
57
|
+
end
|
54
58
|
|
55
59
|
return Bound.new(@cql, @params_metadata, @result_metadata, args) if @params_metadata.empty?
|
56
60
|
|
data/lib/cassandra/table.rb
CHANGED
@@ -231,6 +231,11 @@ module Cassandra
|
|
231
231
|
cql << ';'
|
232
232
|
end
|
233
233
|
|
234
|
+
# @return [String] a CLI-friendly table representation
|
235
|
+
def inspect
|
236
|
+
"#<#{self.class.name}:0x#{self.object_id.to_s(16)} @keyspace=#{@keyspace} @name=#{@name}>"
|
237
|
+
end
|
238
|
+
|
234
239
|
# @return [Boolean] whether this table is equal to the other
|
235
240
|
def eql?(other)
|
236
241
|
other.is_a?(Table) &&
|
@@ -247,7 +252,7 @@ module Cassandra
|
|
247
252
|
# @private
|
248
253
|
def create_partition_key(values)
|
249
254
|
partition_key = @partition_key
|
250
|
-
return nil
|
255
|
+
return nil if partition_key.size > values.size
|
251
256
|
|
252
257
|
if partition_key.one?
|
253
258
|
column = partition_key.first
|
data/lib/cassandra/time_uuid.rb
CHANGED
@@ -19,6 +19,7 @@
|
|
19
19
|
module Cassandra
|
20
20
|
# A variant of UUID which can extract its time component.
|
21
21
|
#
|
22
|
+
# You can use {Cassandra::Uuid::Generator} to generate {Cassandra::TimeUuid}s
|
22
23
|
class TimeUuid < Uuid
|
23
24
|
include Comparable
|
24
25
|
|
@@ -29,18 +30,37 @@ module Cassandra
|
|
29
30
|
t = time_bits - GREGORIAN_OFFSET
|
30
31
|
seconds = t/10_000_000
|
31
32
|
microseconds = (t - seconds * 10_000_000)/10.0
|
33
|
+
|
32
34
|
Time.at(seconds, microseconds).utc
|
33
35
|
end
|
34
36
|
|
37
|
+
# Returns the date component from this UUID as Date.
|
38
|
+
#
|
39
|
+
# This just sugar around {#to_time}
|
40
|
+
#
|
41
|
+
# @return [Date]
|
42
|
+
def to_date
|
43
|
+
to_time.to_date
|
44
|
+
end
|
45
|
+
|
46
|
+
# Compares this timeuuid with another timeuuid
|
47
|
+
#
|
48
|
+
# @param other [Cassandra::TimeUuid] another timeuuid to compare
|
49
|
+
# @see Comparable
|
50
|
+
#
|
51
|
+
# @return [nil] when other is not a {Cassandra::Uuid}
|
52
|
+
# @return [Integer] `-1` when less than `other`, `0` when equal to `other`
|
53
|
+
# and `1` when greater than `other`
|
35
54
|
def <=>(other)
|
36
55
|
return nil unless other.kind_of?(Cassandra::Uuid)
|
37
56
|
c = self.value <=> other.value
|
38
|
-
return c if c == 0
|
57
|
+
return c if c == 0 || !other.is_a?(Cassandra::TimeUuid)
|
39
58
|
self.time_bits <=> other.time_bits
|
40
59
|
end
|
41
60
|
|
42
61
|
protected
|
43
62
|
|
63
|
+
# @private
|
44
64
|
def time_bits
|
45
65
|
n = (value >> 64)
|
46
66
|
t = 0
|
@@ -54,88 +74,6 @@ module Cassandra
|
|
54
74
|
|
55
75
|
# @private
|
56
76
|
LOWER_HALF_MASK = 0xffffffff_ffffffff
|
57
|
-
|
58
|
-
public
|
59
|
-
|
60
|
-
# A UUID version 1, variant 1 generator. It can generate a sequence of UUIDs
|
61
|
-
# with reasonable uniqueness guarantees:
|
62
|
-
#
|
63
|
-
# * The clock ID and node ID components are set to random numbers when the
|
64
|
-
# generator is created.
|
65
|
-
# * If two calls to {#next} happen within the time afforded by the system
|
66
|
-
# clock resolution a counter is incremented and added to the time
|
67
|
-
# component.
|
68
|
-
# * If the clock moves backwards the clock ID is reset to a new random
|
69
|
-
# number.
|
70
|
-
#
|
71
|
-
# Instances of this class are absolutely not threadsafe. You should
|
72
|
-
# never share instances between threads.
|
73
|
-
#
|
74
|
-
class Generator
|
75
|
-
# Create a new UUID generator.
|
76
|
-
#
|
77
|
-
# @param [Integer] node_id an alternate node ID (defaults to a random number)
|
78
|
-
# @param [Integer] clock_id an alternate clock ID (defaults to a random number)
|
79
|
-
#
|
80
|
-
def initialize(node_id=nil, clock_id=nil, clock=Time)
|
81
|
-
@node_id = node_id || (rand(2**47) | 0x010000000000)
|
82
|
-
@clock_id = clock_id || rand(2**16)
|
83
|
-
@clock = clock
|
84
|
-
end
|
85
|
-
|
86
|
-
# Returns a new UUID with a time component that is the current time.
|
87
|
-
#
|
88
|
-
# @return [Cassandra::TimeUuid] a new UUID
|
89
|
-
#
|
90
|
-
def next
|
91
|
-
now = @clock.now
|
92
|
-
usecs = now.to_i * 1_000_000 + now.usec
|
93
|
-
if @last_usecs && @last_usecs - @sequence <= usecs && usecs <= @last_usecs
|
94
|
-
@sequence += 1
|
95
|
-
elsif @last_usecs && @last_usecs > usecs
|
96
|
-
@sequence = 0
|
97
|
-
@clock_id = rand(2**16)
|
98
|
-
else
|
99
|
-
@sequence = 0
|
100
|
-
end
|
101
|
-
@last_usecs = usecs + @sequence
|
102
|
-
from_usecs(@last_usecs)
|
103
|
-
end
|
104
|
-
|
105
|
-
# Returns a new UUID with a time component based on the specified Time.
|
106
|
-
# A piece of jitter is added to ensure that multiple calls with the same
|
107
|
-
# time do not generate the same UUID (if you want determinism you can set
|
108
|
-
# the second parameter to zero).
|
109
|
-
#
|
110
|
-
# @param [Time] time the time to encode into the UUID
|
111
|
-
# @param [Integer] jitter a number of microseconds to add to the time to make it unique
|
112
|
-
# @return [Cassandra::TimeUuid] a new UUID
|
113
|
-
#
|
114
|
-
def from_time(time, jitter=rand(2**16))
|
115
|
-
usecs = time.to_i * 1_000_000 + time.usec + jitter
|
116
|
-
from_usecs(usecs)
|
117
|
-
end
|
118
|
-
|
119
|
-
# @private
|
120
|
-
def from_usecs(usecs)
|
121
|
-
t = GREGORIAN_OFFSET + usecs * 10
|
122
|
-
time_hi = t & 0x0fff000000000000
|
123
|
-
time_mid = t & 0x0000ffff00000000
|
124
|
-
time_low = t & 0x00000000ffffffff
|
125
|
-
version = 1
|
126
|
-
clock_id = @clock_id & 0x3fff
|
127
|
-
node_id = @node_id & 0xffffffffffff
|
128
|
-
variant = 0x8000
|
129
|
-
n = (time_low << 96) | (time_mid << 48) | (time_hi << 16)
|
130
|
-
n |= version << 76
|
131
|
-
n |= (clock_id | variant) << 48
|
132
|
-
n |= node_id
|
133
|
-
TimeUuid.new(n)
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
private
|
138
|
-
|
139
77
|
# @private
|
140
78
|
GREGORIAN_OFFSET = 122192928000000000
|
141
79
|
end
|