right_support 2.8.8 → 2.8.9
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.
- data/VERSION +1 -1
- data/lib/right_support/db/cassandra_model.rb +46 -25
- data/right_support.gemspec +2 -2
- metadata +4 -4
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.8.
|
1
|
+
2.8.9
|
@@ -405,27 +405,30 @@ module RightSupport::DB
|
|
405
405
|
rows
|
406
406
|
end
|
407
407
|
|
408
|
-
# This method is an attempt to circumvent the Cassandra gem limitation of returning only 100 columns for wide rows
|
409
|
-
#
|
410
|
-
#
|
411
|
-
#
|
408
|
+
# This method is an attempt to circumvent the Cassandra gem limitation of returning only 100 columns for wide rows,
|
409
|
+
# and also to help reliably iterate through a column family when the node is busy and experiencing many timeouts.
|
410
|
+
#
|
411
|
+
# Internally, it uses Cassandra#get_indexed_slices to find rows that match your index constraint; when it finds
|
412
|
+
# a wide row (with more than 1,000 columns), it continues to iterate through the columns of that row
|
412
413
|
#
|
413
414
|
# == Parameters:
|
414
415
|
# @param [String] index column name
|
415
416
|
# @param [String] index column value
|
416
417
|
#
|
417
418
|
# == Yields:
|
418
|
-
# @yield [Array<String, Array<CassandraThrift::ColumnOrSuperColumn>>]
|
419
|
+
# @yield [Array<String, Array<CassandraThrift::ColumnOrSuperColumn>>] array containing index column value passed in and an array of columns matching the index query
|
419
420
|
def stream_all_indexed_slices(index, key)
|
420
421
|
expr = do_op(:create_idx_expr, index, key, "EQ")
|
421
|
-
|
422
422
|
start_row = ''
|
423
|
-
max_row_count = 100
|
424
|
-
max_initial_column_count = 1000 # number of columns to retrieve in the initial 2ndary index search
|
425
|
-
max_additional_column_count = 10000 # Number of columns to retrieve in a batch once we're targetting a single (long) row
|
426
423
|
|
427
424
|
# Loop over all CF rows, with batches of X
|
428
425
|
while (start_row != nil)
|
426
|
+
# Reset these to their initieral values on every iteration thru the loop, in case
|
427
|
+
# we backed off due to timeouts (see rescue clauses below)
|
428
|
+
max_row_count = 100 # how many rows to grab at once
|
429
|
+
max_initial_column_count = 1000 # how much to grab at first for each row
|
430
|
+
max_additional_column_count = 1000 # how much to grab in each chunk of a long row
|
431
|
+
|
429
432
|
clause = do_op(:create_idx_clause, [expr], start_row, max_row_count)
|
430
433
|
|
431
434
|
# Now, for each batch of rows, make sure don't ask for "ALL" columns of each row, to avoid hitting rows with a huge amount of columns,
|
@@ -433,16 +436,14 @@ module RightSupport::DB
|
|
433
436
|
begin
|
434
437
|
rows = self.conn.get_indexed_slices(column_family, clause, :count => max_initial_column_count)
|
435
438
|
rescue Exception => e
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
timeout_retries += 1
|
439
|
+
if retryable_read_timeout?(e)
|
440
|
+
logger.error "CassandraModel#stream_all_indexed_slices retrying get_indexed_slices with fewer rows/cols due to a %s: %s @ %s (cf='%s' start_row='%s' count=%d)" %
|
441
|
+
[e.class.name, e.message, e.backtrace.first, column_family, start_row, max_row_count]
|
442
|
+
max_row_count /= 10 if max_row_count > 1
|
443
|
+
max_initial_column_count /= 10 if max_initial_column_count > 1
|
442
444
|
retry
|
443
445
|
else
|
444
|
-
|
445
|
-
raise e
|
446
|
+
raise
|
446
447
|
end
|
447
448
|
end
|
448
449
|
|
@@ -467,16 +468,13 @@ module RightSupport::DB
|
|
467
468
|
:start => last_column_name,
|
468
469
|
:slices_not_hash => true ).first.columns[1..-1]
|
469
470
|
rescue Exception => e
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
if (wrapped_timeout || unwrapped_timeout || unwrapped_disconnect) && (timeout_retries < retry_timeout)
|
475
|
-
timeout_retries += 1
|
471
|
+
if retryable_read_timeout?(e)
|
472
|
+
logger.error "CassandraModel#stream_all_indexed_slices retrying get_range with fewer rows/cols due to a %s: %s @ %s (cf='%s' row='%s' start='%s' count=%d)" %
|
473
|
+
[e.class.name, e.message, e.backtrace.first, column_family, row_key, last_column_name, max_additional_column_count]
|
474
|
+
max_additional_column_count /= 10 if max_additional_column_count > 1
|
476
475
|
retry
|
477
476
|
else
|
478
|
-
|
479
|
-
raise e
|
477
|
+
raise
|
480
478
|
end
|
481
479
|
end
|
482
480
|
|
@@ -693,6 +691,29 @@ module RightSupport::DB
|
|
693
691
|
end
|
694
692
|
end
|
695
693
|
|
694
|
+
# Determine whether an exception can safely be retried, if the operation being performed
|
695
|
+
# was a read (i.e. is idempotent).
|
696
|
+
# @param [Exception] e the exception in question
|
697
|
+
# @return [Boolean] true if yes, false otherwise
|
698
|
+
def retryable_read_timeout?(e)
|
699
|
+
# Thrift RPC timeout that has been "improved" by cassandra gem's moronic exception-wrapping
|
700
|
+
wrapped_timeout = e.is_a?(CassandraThrift::TimedOutException)
|
701
|
+
|
702
|
+
# I have no idea what these are, but they show up when we have a local socket-read timeout after 10s
|
703
|
+
# Probably due to this line from the thrift gem (in lib/thrift/transport/socket.rb)
|
704
|
+
# raise TransportException.new(TransportException::TIMED_OUT, "Socket: Timed out reading #{sz} bytes from #{@desc}")
|
705
|
+
# The TransportException gets wrapped into a CassandraThrift::Cassandra::Client::TransportException and in the process
|
706
|
+
# the type is lost and the message is promoted to "type"
|
707
|
+
bogus_timeout = e.is_a?(Thrift::TransportException) && e.type.is_a?(String) && e.type =~ /Timed out/i
|
708
|
+
|
709
|
+
# Thrift RPC timeout
|
710
|
+
unwrapped_timeout = e.is_a?(Thrift::TransportException) && (e.type == Thrift::TransportException::TIMED_OUT)
|
711
|
+
|
712
|
+
# Thrift socket disconnect
|
713
|
+
unwrapped_disconnect = e.is_a?(Thrift::TransportException) && (e.type == Thrift::TransportException::NOT_OPEN)
|
714
|
+
|
715
|
+
wrapped_timeout || bogus_timeout || unwrapped_timeout || unwrapped_disconnect
|
716
|
+
end
|
696
717
|
end # self
|
697
718
|
|
698
719
|
attr_accessor :key, :attributes
|
data/right_support.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "right_support"
|
8
|
-
s.version = "2.8.
|
8
|
+
s.version = "2.8.9"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Tony Spataro", "Sergey Sergyenko", "Ryan Williamson", "Lee Kirchhoff", "Alexey Karpik", "Scott Messier"]
|
12
|
-
s.date = "2014-01-
|
12
|
+
s.date = "2014-01-13"
|
13
13
|
s.description = "A toolkit of useful, reusable foundation code created by RightScale."
|
14
14
|
s.email = "support@rightscale.com"
|
15
15
|
s.extra_rdoc_files = [
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: right_support
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 61
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 2
|
8
8
|
- 8
|
9
|
-
-
|
10
|
-
version: 2.8.
|
9
|
+
- 9
|
10
|
+
version: 2.8.9
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Tony Spataro
|
@@ -20,7 +20,7 @@ autorequire:
|
|
20
20
|
bindir: bin
|
21
21
|
cert_chain: []
|
22
22
|
|
23
|
-
date: 2014-01-
|
23
|
+
date: 2014-01-13 00:00:00 Z
|
24
24
|
dependencies:
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
version_requirements: &id001 !ruby/object:Gem::Requirement
|