cassandra-driver 2.1.7 → 3.0.0.beta.1
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 +8 -8
- data/README.md +31 -53
- data/lib/cassandra.rb +22 -3
- data/lib/cassandra/aggregate.rb +109 -0
- data/lib/cassandra/argument.rb +51 -0
- data/lib/cassandra/auth/providers/password.rb +7 -4
- data/lib/cassandra/cluster.rb +14 -3
- data/lib/cassandra/cluster/client.rb +56 -34
- data/lib/cassandra/cluster/connector.rb +6 -6
- data/lib/cassandra/cluster/control_connection.rb +204 -251
- data/lib/cassandra/cluster/metadata.rb +2 -0
- data/lib/cassandra/cluster/schema.rb +131 -209
- data/lib/cassandra/cluster/schema/cql_type_parser.rb +104 -0
- data/lib/cassandra/cluster/schema/fetchers.rb +1174 -0
- data/lib/cassandra/cluster/schema/{type_parser.rb → fqcn_type_parser.rb} +7 -3
- data/lib/cassandra/column.rb +2 -2
- data/lib/cassandra/driver.rb +27 -9
- data/lib/cassandra/errors.rb +179 -25
- data/lib/cassandra/execution/info.rb +8 -1
- data/lib/cassandra/execution/options.rb +34 -0
- data/lib/cassandra/execution/trace.rb +42 -10
- data/lib/cassandra/function.rb +150 -0
- data/lib/cassandra/future.rb +66 -35
- data/lib/cassandra/host.rb +7 -4
- data/lib/cassandra/keyspace.rb +112 -13
- data/lib/cassandra/load_balancing.rb +1 -1
- data/lib/cassandra/protocol.rb +9 -3
- data/lib/cassandra/protocol/coder.rb +434 -155
- data/lib/cassandra/protocol/cql_byte_buffer.rb +43 -0
- data/lib/cassandra/protocol/cql_protocol_handler.rb +4 -1
- data/lib/cassandra/protocol/request.rb +4 -0
- data/lib/cassandra/protocol/requests/auth_response_request.rb +5 -1
- data/lib/cassandra/protocol/requests/batch_request.rb +7 -2
- data/lib/cassandra/protocol/requests/credentials_request.rb +5 -1
- data/lib/cassandra/protocol/requests/execute_request.rb +16 -10
- data/lib/cassandra/protocol/requests/prepare_request.rb +12 -3
- data/lib/cassandra/protocol/requests/query_request.rb +20 -11
- data/lib/cassandra/protocol/responses/already_exists_error_response.rb +4 -4
- data/lib/cassandra/protocol/responses/error_response.rb +14 -14
- data/lib/cassandra/protocol/responses/function_failure_error_response.rb +41 -0
- data/lib/cassandra/protocol/responses/prepared_result_response.rb +12 -9
- data/lib/cassandra/protocol/responses/raw_rows_result_response.rb +5 -3
- data/lib/cassandra/protocol/responses/read_failure_error_response.rb +43 -0
- data/lib/cassandra/protocol/responses/read_timeout_error_response.rb +4 -4
- data/lib/cassandra/protocol/responses/ready_response.rb +5 -1
- data/lib/cassandra/protocol/responses/result_response.rb +3 -3
- data/lib/cassandra/protocol/responses/rows_result_response.rb +2 -2
- data/lib/cassandra/protocol/responses/schema_change_event_response.rb +25 -24
- data/lib/cassandra/protocol/responses/schema_change_result_response.rb +20 -23
- data/lib/cassandra/protocol/responses/set_keyspace_result_response.rb +2 -2
- data/lib/cassandra/protocol/responses/unavailable_error_response.rb +4 -4
- data/lib/cassandra/protocol/responses/unprepared_error_response.rb +4 -4
- data/lib/cassandra/protocol/responses/write_failure_error_response.rb +45 -0
- data/lib/cassandra/protocol/responses/write_timeout_error_response.rb +4 -4
- data/lib/cassandra/protocol/v1.rb +38 -13
- data/lib/cassandra/protocol/v3.rb +34 -29
- data/lib/cassandra/protocol/v4.rb +334 -0
- data/lib/cassandra/result.rb +10 -9
- data/lib/cassandra/retry.rb +17 -3
- data/lib/cassandra/retry/policies/default.rb +9 -3
- data/lib/cassandra/session.rb +15 -7
- data/lib/cassandra/statement.rb +5 -0
- data/lib/cassandra/statements/batch.rb +36 -12
- data/lib/cassandra/statements/bound.rb +2 -1
- data/lib/cassandra/statements/prepared.rb +106 -35
- data/lib/cassandra/statements/simple.rb +4 -2
- data/lib/cassandra/table.rb +70 -105
- data/lib/cassandra/time.rb +98 -0
- data/lib/cassandra/time_uuid.rb +1 -1
- data/lib/cassandra/tuple.rb +7 -0
- data/lib/cassandra/types.rb +472 -272
- data/lib/cassandra/udt.rb +10 -0
- data/lib/cassandra/util.rb +32 -1
- data/lib/cassandra/uuid.rb +6 -1
- data/lib/cassandra/uuid/generator.rb +7 -7
- data/lib/cassandra/version.rb +1 -1
- data/lib/datastax/cassandra.rb +5 -2
- metadata +16 -6
| @@ -208,8 +208,10 @@ module Cassandra | |
| 208 208 | 
             
                    return @futures.error(Errors::ClientError.new("Positional arguments are not supported by the current version of Apache Cassandra")) if !statement.params.empty? && @connection_options.protocol_version == 1
         | 
| 209 209 |  | 
| 210 210 | 
             
                    timestamp = nil
         | 
| 211 | 
            -
                    timestamp = Time.now if @connection_options.client_timestamps? && @connection_options.protocol_version > 2
         | 
| 212 | 
            -
                     | 
| 211 | 
            +
                    timestamp = ::Time.now if @connection_options.client_timestamps? && @connection_options.protocol_version > 2
         | 
| 212 | 
            +
                    payload   = nil
         | 
| 213 | 
            +
                    payload   = options.payload if  @connection_options.protocol_version >= 4
         | 
| 214 | 
            +
                    request   = Protocol::QueryRequest.new(statement.cql, statement.params, statement.params_types, options.consistency, options.serial_consistency, options.page_size, options.paging_state, options.trace?, statement.params_names, timestamp, payload)
         | 
| 213 215 | 
             
                    timeout   = options.timeout
         | 
| 214 216 | 
             
                    promise   = @futures.promise
         | 
| 215 217 |  | 
| @@ -222,7 +224,9 @@ module Cassandra | |
| 222 224 | 
             
                  end
         | 
| 223 225 |  | 
| 224 226 | 
             
                  def prepare(cql, options)
         | 
| 225 | 
            -
                     | 
| 227 | 
            +
                    payload = nil
         | 
| 228 | 
            +
                    payload = options.payload if  @connection_options.protocol_version >= 4
         | 
| 229 | 
            +
                    request = Protocol::PrepareRequest.new(cql, options.trace?, payload)
         | 
| 226 230 | 
             
                    timeout = options.timeout
         | 
| 227 231 | 
             
                    promise = @futures.promise
         | 
| 228 232 |  | 
| @@ -237,10 +241,12 @@ module Cassandra | |
| 237 241 |  | 
| 238 242 | 
             
                  def execute(statement, options)
         | 
| 239 243 | 
             
                    timestamp       = nil
         | 
| 240 | 
            -
                    timestamp       = Time.now if @connection_options.client_timestamps? && @connection_options.protocol_version > 2
         | 
| 244 | 
            +
                    timestamp       = ::Time.now if @connection_options.client_timestamps? && @connection_options.protocol_version > 2
         | 
| 245 | 
            +
                    payload         = nil
         | 
| 246 | 
            +
                    payload         = options.payload if  @connection_options.protocol_version >= 4
         | 
| 241 247 | 
             
                    timeout         = options.timeout
         | 
| 242 248 | 
             
                    result_metadata = statement.result_metadata
         | 
| 243 | 
            -
                    request         = Protocol::ExecuteRequest.new(nil, statement.params_types, statement.params, result_metadata.nil?, options.consistency, options.serial_consistency, options.page_size, options.paging_state, options.trace?, timestamp)
         | 
| 249 | 
            +
                    request         = Protocol::ExecuteRequest.new(nil, statement.params_types, statement.params, result_metadata.nil?, options.consistency, options.serial_consistency, options.page_size, options.paging_state, options.trace?, timestamp, payload)
         | 
| 244 250 | 
             
                    promise         = @futures.promise
         | 
| 245 251 |  | 
| 246 252 | 
             
                    keyspace = @keyspace
         | 
| @@ -255,9 +261,11 @@ module Cassandra | |
| 255 261 | 
             
                    return @futures.error(Errors::ClientError.new("Batch statements are not supported by the current version of Apache Cassandra")) if @connection_options.protocol_version < 2
         | 
| 256 262 |  | 
| 257 263 | 
             
                    timestamp = nil
         | 
| 258 | 
            -
                    timestamp = Time.now if @connection_options.client_timestamps? && @connection_options.protocol_version > 2
         | 
| 264 | 
            +
                    timestamp = ::Time.now if @connection_options.client_timestamps? && @connection_options.protocol_version > 2
         | 
| 265 | 
            +
                    payload   = nil
         | 
| 266 | 
            +
                    payload   = options.payload if  @connection_options.protocol_version >= 4
         | 
| 259 267 | 
             
                    timeout   = options.timeout
         | 
| 260 | 
            -
                    request   = Protocol::BatchRequest.new(BATCH_TYPES[statement.type], options.consistency, options.trace?, options.serial_consistency, timestamp)
         | 
| 268 | 
            +
                    request   = Protocol::BatchRequest.new(BATCH_TYPES[statement.type], options.consistency, options.trace?, options.serial_consistency, timestamp, payload)
         | 
| 261 269 | 
             
                    keyspace  = @keyspace
         | 
| 262 270 | 
             
                    plan      = @load_balancing_policy.plan(keyspace, statement, options)
         | 
| 263 271 | 
             
                    promise   = @futures.promise
         | 
| @@ -467,8 +475,7 @@ module Cassandra | |
| 467 475 | 
             
                          prepare_and_send_request_by_plan(host, connection, promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
         | 
| 468 476 | 
             
                        else
         | 
| 469 477 | 
             
                          s.on_failure do |e|
         | 
| 470 | 
            -
                             | 
| 471 | 
            -
                            when Errors::HostError
         | 
| 478 | 
            +
                            if e.is_a?(Errors::HostError) || (e.is_a?(Errors::TimeoutError) && statement.idempotent?)
         | 
| 472 479 | 
             
                              errors ||= {}
         | 
| 473 480 | 
             
                              errors[host] = e
         | 
| 474 481 | 
             
                              execute_by_plan(promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
         | 
| @@ -502,8 +509,7 @@ module Cassandra | |
| 502 509 | 
             
                          do_send_request_by_plan(host, connection, promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
         | 
| 503 510 | 
             
                        else
         | 
| 504 511 | 
             
                          prepare.on_failure do |e|
         | 
| 505 | 
            -
                             | 
| 506 | 
            -
                            when Errors::HostError
         | 
| 512 | 
            +
                            if e.is_a?(Errors::HostError) || (e.is_a?(Errors::TimeoutError) && statement.idempotent?)
         | 
| 507 513 | 
             
                              errors ||= {}
         | 
| 508 514 | 
             
                              errors[host] = e
         | 
| 509 515 | 
             
                              execute_by_plan(promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
         | 
| @@ -514,6 +520,8 @@ module Cassandra | |
| 514 520 | 
             
                        end
         | 
| 515 521 | 
             
                      end
         | 
| 516 522 | 
             
                    end
         | 
| 523 | 
            +
                  rescue => e
         | 
| 524 | 
            +
                    promise.break(e)
         | 
| 517 525 | 
             
                  end
         | 
| 518 526 |  | 
| 519 527 | 
             
                  def batch_by_plan(promise, keyspace, statement, options, request, plan, timeout, errors = nil, hosts = [])
         | 
| @@ -541,8 +549,7 @@ module Cassandra | |
| 541 549 | 
             
                          batch_and_send_request_by_plan(host, connection, promise, keyspace, statement, request, options, plan, timeout, errors, hosts)
         | 
| 542 550 | 
             
                        else
         | 
| 543 551 | 
             
                          s.on_failure do |e|
         | 
| 544 | 
            -
                             | 
| 545 | 
            -
                            when Errors::HostError
         | 
| 552 | 
            +
                            if e.is_a?(Errors::HostError) || (e.is_a?(Errors::TimeoutError) && statement.idempotent?)
         | 
| 546 553 | 
             
                              errors ||= {}
         | 
| 547 554 | 
             
                              errors[host] = e
         | 
| 548 555 | 
             
                              batch_by_plan(promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
         | 
| @@ -601,8 +608,7 @@ module Cassandra | |
| 601 608 | 
             
                          do_send_request_by_plan(host, connection, promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
         | 
| 602 609 | 
             
                        else
         | 
| 603 610 | 
             
                          f.on_failure do |e|
         | 
| 604 | 
            -
                             | 
| 605 | 
            -
                            when Errors::HostError
         | 
| 611 | 
            +
                            if e.is_a?(Errors::HostError) || (e.is_a?(Errors::TimeoutError) && statement.idempotent?)
         | 
| 606 612 | 
             
                              errors ||= {}
         | 
| 607 613 | 
             
                              errors[host] = e
         | 
| 608 614 | 
             
                              batch_by_plan(promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
         | 
| @@ -640,8 +646,7 @@ module Cassandra | |
| 640 646 | 
             
                          do_send_request_by_plan(host, connection, promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
         | 
| 641 647 | 
             
                        else
         | 
| 642 648 | 
             
                          s.on_failure do |e|
         | 
| 643 | 
            -
                             | 
| 644 | 
            -
                            when Errors::HostError
         | 
| 649 | 
            +
                            if e.is_a?(Errors::HostError) || (e.is_a?(Errors::TimeoutError) && statement.idempotent?)
         | 
| 645 650 | 
             
                              errors ||= {}
         | 
| 646 651 | 
             
                              errors[host] = e
         | 
| 647 652 | 
             
                              send_request_by_plan(promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
         | 
| @@ -693,8 +698,7 @@ module Cassandra | |
| 693 698 | 
             
                                do_send_request_by_plan(host, connection, promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
         | 
| 694 699 | 
             
                              else
         | 
| 695 700 | 
             
                                prepare.on_failure do |e|
         | 
| 696 | 
            -
                                   | 
| 697 | 
            -
                                  when Errors::HostError
         | 
| 701 | 
            +
                                  if e.is_a?(Errors::HostError) || (e.is_a?(Errors::TimeoutError) && statement.idempotent?)
         | 
| 698 702 | 
             
                                    errors ||= {}
         | 
| 699 703 | 
             
                                    errors[host] = e
         | 
| 700 704 | 
             
                                    execute_by_plan(promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
         | 
| @@ -705,10 +709,9 @@ module Cassandra | |
| 705 709 | 
             
                              end
         | 
| 706 710 | 
             
                            end
         | 
| 707 711 | 
             
                          when Protocol::ErrorResponse
         | 
| 708 | 
            -
                            error = r.to_error(statement)
         | 
| 712 | 
            +
                            error = r.to_error(keyspace, statement, options, hosts, request.consistency, retries)
         | 
| 709 713 |  | 
| 710 | 
            -
                             | 
| 711 | 
            -
                            when Errors::HostError
         | 
| 714 | 
            +
                            if error.is_a?(Errors::HostError) || (error.is_a?(Errors::TimeoutError) && statement.idempotent?)
         | 
| 712 715 | 
             
                              errors ||= {}
         | 
| 713 716 | 
             
                              errors[host] = error
         | 
| 714 717 |  | 
| @@ -725,7 +728,7 @@ module Cassandra | |
| 725 728 | 
             
                            end
         | 
| 726 729 | 
             
                          when Protocol::SetKeyspaceResultResponse
         | 
| 727 730 | 
             
                            @keyspace = r.keyspace
         | 
| 728 | 
            -
                            promise.fulfill(Results::Void.new(r.trace_id, keyspace, statement, options, hosts, request.consistency, retries, self, @futures))
         | 
| 731 | 
            +
                            promise.fulfill(Results::Void.new(r.custom_payload, r.warnings, r.trace_id, keyspace, statement, options, hosts, request.consistency, retries, self, @futures))
         | 
| 729 732 | 
             
                          when Protocol::PreparedResultResponse
         | 
| 730 733 | 
             
                            cql = request.cql
         | 
| 731 734 | 
             
                            synchronize do
         | 
| @@ -733,12 +736,16 @@ module Cassandra | |
| 733 736 | 
             
                              @preparing_statements[host].delete(cql)
         | 
| 734 737 | 
             
                            end
         | 
| 735 738 |  | 
| 736 | 
            -
                             | 
| 739 | 
            +
                            metadata = r.metadata
         | 
| 740 | 
            +
                            pk_idx   = r.pk_idx
         | 
| 741 | 
            +
                            pk_idx ||= @schema.get_pk_idx(metadata)
         | 
| 742 | 
            +
             | 
| 743 | 
            +
                            promise.fulfill(Statements::Prepared.new(r.custom_payload, r.warnings, cql, metadata, r.result_metadata, pk_idx, r.trace_id, keyspace, statement, options, hosts, request.consistency, retries, self, @connection_options))
         | 
| 737 744 | 
             
                          when Protocol::RawRowsResultResponse
         | 
| 738 745 | 
             
                            r.materialize(statement.result_metadata)
         | 
| 739 | 
            -
                            promise.fulfill(Results::Paged.new(r.rows, r.paging_state, r.trace_id, keyspace, statement, options, hosts, request.consistency, retries, self, @futures))
         | 
| 746 | 
            +
                            promise.fulfill(Results::Paged.new(r.custom_payload, r.warnings, r.rows, r.paging_state, r.trace_id, keyspace, statement, options, hosts, request.consistency, retries, self, @futures))
         | 
| 740 747 | 
             
                          when Protocol::RowsResultResponse
         | 
| 741 | 
            -
                            promise.fulfill(Results::Paged.new(r.rows, r.paging_state, r.trace_id, keyspace, statement, options, hosts, request.consistency, retries, self, @futures))
         | 
| 748 | 
            +
                            promise.fulfill(Results::Paged.new(r.custom_payload, r.warnings, r.rows, r.paging_state, r.trace_id, keyspace, statement, options, hosts, request.consistency, retries, self, @futures))
         | 
| 742 749 | 
             
                          when Protocol::SchemaChangeResultResponse
         | 
| 743 750 | 
             
                            @schema.delete_keyspace(r.keyspace) if r.change == 'DROPPED' && r.target == Protocol::Constants::SCHEMA_CHANGE_TARGET_KEYSPACE
         | 
| 744 751 |  | 
| @@ -749,10 +756,10 @@ module Cassandra | |
| 749 756 | 
             
                                  @logger.error("Schema agreement failure (#{e.class.name}: #{e.message})")
         | 
| 750 757 | 
             
                                end
         | 
| 751 758 | 
             
                              end
         | 
| 752 | 
            -
                              promise.fulfill(Results::Void.new(r.trace_id, keyspace, statement, options, hosts, request.consistency, retries, self, @futures))
         | 
| 759 | 
            +
                              promise.fulfill(Results::Void.new(r.custom_payload, r.warnings, r.trace_id, keyspace, statement, options, hosts, request.consistency, retries, self, @futures))
         | 
| 753 760 | 
             
                            end
         | 
| 754 761 | 
             
                          else
         | 
| 755 | 
            -
                            promise.fulfill(Results::Void.new(r.trace_id, keyspace, statement, options, hosts, request.consistency, retries, self, @futures))
         | 
| 762 | 
            +
                            promise.fulfill(Results::Void.new(r.custom_payload, r.warnings, r.trace_id, keyspace, statement, options, hosts, request.consistency, retries, self, @futures))
         | 
| 756 763 | 
             
                          end
         | 
| 757 764 |  | 
| 758 765 | 
             
                          if decision
         | 
| @@ -760,12 +767,25 @@ module Cassandra | |
| 760 767 | 
             
                            when Retry::Decisions::Retry
         | 
| 761 768 | 
             
                              request.consistency = decision.consistency
         | 
| 762 769 | 
             
                              do_send_request_by_plan(host, connection, promise, keyspace, statement, options, request, plan, timeout, errors, hosts, retries + 1)
         | 
| 770 | 
            +
                            when Retry::Decisions::TryNextHost
         | 
| 771 | 
            +
                              errors ||= {}
         | 
| 772 | 
            +
                              errors[host] = r.to_error(keyspace, statement, options, hosts, request.consistency, retries)
         | 
| 773 | 
            +
                              case request
         | 
| 774 | 
            +
                              when Protocol::QueryRequest, Protocol::PrepareRequest
         | 
| 775 | 
            +
                                send_request_by_plan(promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
         | 
| 776 | 
            +
                              when Protocol::ExecuteRequest
         | 
| 777 | 
            +
                                execute_by_plan(promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
         | 
| 778 | 
            +
                              when Protocol::BatchRequest
         | 
| 779 | 
            +
                                batch_by_plan(promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
         | 
| 780 | 
            +
                              else
         | 
| 781 | 
            +
                                promise.break(e)
         | 
| 782 | 
            +
                              end
         | 
| 763 783 | 
             
                            when Retry::Decisions::Ignore
         | 
| 764 | 
            -
                              promise.fulfill(Results::Void.new(r.trace_id, keyspace, statement, options, hosts, request.consistency, retries, self, @futures))
         | 
| 784 | 
            +
                              promise.fulfill(Results::Void.new(r.custom_payload, r.warnings, r.trace_id, keyspace, statement, options, hosts, request.consistency, retries, self, @futures))
         | 
| 765 785 | 
             
                            when Retry::Decisions::Reraise
         | 
| 766 | 
            -
                              promise.break(r.to_error(statement))
         | 
| 786 | 
            +
                              promise.break(r.to_error(keyspace, statement, options, hosts, request.consistency, retries))
         | 
| 767 787 | 
             
                            else
         | 
| 768 | 
            -
                              promise.break(r.to_error(statement))
         | 
| 788 | 
            +
                              promise.break(r.to_error(keyspace, statement, options, hosts, request.consistency, retries))
         | 
| 769 789 | 
             
                            end
         | 
| 770 790 | 
             
                          end
         | 
| 771 791 | 
             
                        rescue => e
         | 
| @@ -788,6 +808,8 @@ module Cassandra | |
| 788 808 | 
             
                        end
         | 
| 789 809 | 
             
                      end
         | 
| 790 810 | 
             
                    end
         | 
| 811 | 
            +
                  rescue => e
         | 
| 812 | 
            +
                    promise.break(e)
         | 
| 791 813 | 
             
                  end
         | 
| 792 814 |  | 
| 793 815 | 
             
                  def wait_for_schema_agreement(connection, schedule)
         | 
| @@ -848,7 +870,7 @@ module Cassandra | |
| 848 870 | 
             
                        @keyspace = r.keyspace
         | 
| 849 871 | 
             
                        nil
         | 
| 850 872 | 
             
                      when Protocol::ErrorResponse
         | 
| 851 | 
            -
                        raise r.to_error(Statements::Simple.new("USE #{Util.escape_name(keyspace)}"))
         | 
| 873 | 
            +
                        raise r.to_error(nil, Statements::Simple.new("USE #{Util.escape_name(keyspace)}"), VOID_OPTIONS, EMPTY_LIST, :one, 0)
         | 
| 852 874 | 
             
                      else
         | 
| 853 875 | 
             
                        raise Errors::InternalError, "Unexpected response #{r.inspect}"
         | 
| 854 876 | 
             
                      end
         | 
| @@ -884,7 +906,7 @@ module Cassandra | |
| 884 906 | 
             
                        end
         | 
| 885 907 | 
             
                        id
         | 
| 886 908 | 
             
                      when Protocol::ErrorResponse
         | 
| 887 | 
            -
                        raise r.to_error(VOID_STATEMENT)
         | 
| 909 | 
            +
                        raise r.to_error(nil, VOID_STATEMENT, VOID_OPTIONS, EMPTY_LIST, :one, 0)
         | 
| 888 910 | 
             
                      else
         | 
| 889 911 | 
             
                        raise Errors::InternalError, "Unexpected response #{r.inspect}"
         | 
| 890 912 | 
             
                      end
         | 
| @@ -903,7 +925,7 @@ module Cassandra | |
| 903 925 | 
             
                      when Protocol::RowsResultResponse
         | 
| 904 926 | 
             
                        r.rows
         | 
| 905 927 | 
             
                      when Protocol::ErrorResponse
         | 
| 906 | 
            -
                        raise r.to_error(VOID_STATEMENT)
         | 
| 928 | 
            +
                        raise r.to_error(nil, VOID_STATEMENT, VOID_OPTIONS, EMPTY_LIST, :one, 0)
         | 
| 907 929 | 
             
                      else
         | 
| 908 930 | 
             
                        raise Errors::InternalError, "Unexpected response #{r.inspect}"
         | 
| 909 931 | 
             
                      end
         | 
| @@ -181,20 +181,20 @@ module Cassandra | |
| 181 181 | 
             
                          if credentials
         | 
| 182 182 | 
             
                            send_credentials(connection, credentials)
         | 
| 183 183 | 
             
                          else
         | 
| 184 | 
            -
                            Ione::Future.failed(Errors::AuthenticationError.new('Server requested authentication, but client was not configured to authenticate'))
         | 
| 184 | 
            +
                            Ione::Future.failed(Errors::AuthenticationError.new('Server requested authentication, but client was not configured to authenticate', nil, nil, nil, VOID_STATEMENT, VOID_OPTIONS, EMPTY_LIST, :one, 0))
         | 
| 185 185 | 
             
                          end
         | 
| 186 186 | 
             
                        else
         | 
| 187 187 | 
             
                          authenticator = @connection_options.create_authenticator(r.authentication_class)
         | 
| 188 188 | 
             
                          if authenticator
         | 
| 189 189 | 
             
                            challenge_response_cycle(connection, authenticator, authenticator.initial_response)
         | 
| 190 190 | 
             
                          else
         | 
| 191 | 
            -
                            Ione::Future.failed(Errors::AuthenticationError.new('Server requested authentication, but client was not configured to authenticate'))
         | 
| 191 | 
            +
                            Ione::Future.failed(Errors::AuthenticationError.new('Server requested authentication, but client was not configured to authenticate', nil, nil, nil, VOID_STATEMENT, VOID_OPTIONS, EMPTY_LIST, :one, 0))
         | 
| 192 192 | 
             
                          end
         | 
| 193 193 | 
             
                        end
         | 
| 194 194 | 
             
                      when Protocol::ReadyResponse
         | 
| 195 195 | 
             
                        ::Ione::Future.resolved(connection)
         | 
| 196 196 | 
             
                      when Protocol::ErrorResponse
         | 
| 197 | 
            -
                        ::Ione::Future.failed(r.to_error(VOID_STATEMENT))
         | 
| 197 | 
            +
                        ::Ione::Future.failed(r.to_error(nil, VOID_STATEMENT, VOID_OPTIONS, EMPTY_LIST, :one, 0))
         | 
| 198 198 | 
             
                      else
         | 
| 199 199 | 
             
                        ::Ione::Future.failed(Errors::InternalError.new("Unexpected response #{r.inspect}"))
         | 
| 200 200 | 
             
                      end
         | 
| @@ -207,7 +207,7 @@ module Cassandra | |
| 207 207 | 
             
                      when Protocol::SupportedResponse
         | 
| 208 208 | 
             
                        r.options
         | 
| 209 209 | 
             
                      when Protocol::ErrorResponse
         | 
| 210 | 
            -
                        raise r.to_error(VOID_STATEMENT)
         | 
| 210 | 
            +
                        raise r.to_error(nil, VOID_STATEMENT, VOID_OPTIONS, EMPTY_LIST, :one, 0)
         | 
| 211 211 | 
             
                      else
         | 
| 212 212 | 
             
                        raise Errors::InternalError, "Unexpected response #{r.inspect}"
         | 
| 213 213 | 
             
                      end
         | 
| @@ -220,7 +220,7 @@ module Cassandra | |
| 220 220 | 
             
                      when Protocol::ReadyResponse
         | 
| 221 221 | 
             
                        connection
         | 
| 222 222 | 
             
                      when Protocol::ErrorResponse
         | 
| 223 | 
            -
                        raise r.to_error(VOID_STATEMENT)
         | 
| 223 | 
            +
                        raise r.to_error(nil, VOID_STATEMENT, VOID_OPTIONS, EMPTY_LIST, :one, 0)
         | 
| 224 224 | 
             
                      else
         | 
| 225 225 | 
             
                        raise Errors::InternalError, "Unexpected response #{r.inspect}"
         | 
| 226 226 | 
             
                      end
         | 
| @@ -237,7 +237,7 @@ module Cassandra | |
| 237 237 | 
             
                        authenticator.authentication_successful(r.token) rescue nil
         | 
| 238 238 | 
             
                        ::Ione::Future.resolved(connection)
         | 
| 239 239 | 
             
                      when Protocol::ErrorResponse
         | 
| 240 | 
            -
                        ::Ione::Future.failed(r.to_error(VOID_STATEMENT))
         | 
| 240 | 
            +
                        ::Ione::Future.failed(r.to_error(nil, VOID_STATEMENT, VOID_OPTIONS, EMPTY_LIST, :one, 0))
         | 
| 241 241 | 
             
                      else
         | 
| 242 242 | 
             
                        ::Ione::Future.failed(Errors::InternalError.new("Unexpected response #{r.inspect}"))
         | 
| 243 243 | 
             
                      end
         | 
| @@ -22,7 +22,10 @@ module Cassandra | |
| 22 22 | 
             
                class ControlConnection
         | 
| 23 23 | 
             
                  include MonitorMixin
         | 
| 24 24 |  | 
| 25 | 
            -
                  def initialize(logger, io_reactor, cluster_registry, cluster_schema, | 
| 25 | 
            +
                  def initialize(logger, io_reactor, cluster_registry, cluster_schema,
         | 
| 26 | 
            +
                                 cluster_metadata, load_balancing_policy,
         | 
| 27 | 
            +
                                 reconnection_policy, address_resolution_policy, connector,
         | 
| 28 | 
            +
                                 connection_options, schema_fetcher)
         | 
| 26 29 | 
             
                    @logger                = logger
         | 
| 27 30 | 
             
                    @io_reactor            = io_reactor
         | 
| 28 31 | 
             
                    @registry              = cluster_registry
         | 
| @@ -33,6 +36,7 @@ module Cassandra | |
| 33 36 | 
             
                    @address_resolver      = address_resolution_policy
         | 
| 34 37 | 
             
                    @connector             = connector
         | 
| 35 38 | 
             
                    @connection_options    = connection_options
         | 
| 39 | 
            +
                    @schema_fetcher        = schema_fetcher
         | 
| 36 40 | 
             
                    @refreshing_statuses   = ::Hash.new(false)
         | 
| 37 41 | 
             
                    @status                = :closed
         | 
| 38 42 | 
             
                    @refreshing_hosts      = false
         | 
| @@ -129,32 +133,14 @@ module Cassandra | |
| 129 133 | 
             
                    @closed_promise.fulfill
         | 
| 130 134 | 
             
                  end
         | 
| 131 135 |  | 
| 132 | 
            -
                  def refresh_schema_async_maybe_retry
         | 
| 133 | 
            -
                    refresh_schema_async.fallback do |e|
         | 
| 134 | 
            -
                      case e
         | 
| 135 | 
            -
                      when Errors::HostError
         | 
| 136 | 
            -
                        refresh_schema_async_retry(e, @reconnection_policy.schedule)
         | 
| 137 | 
            -
                      else
         | 
| 138 | 
            -
                        connection = @connection
         | 
| 139 | 
            -
                        connection && connection.close(e)
         | 
| 140 | 
            -
             | 
| 141 | 
            -
                        Ione::Future.failed(e)
         | 
| 142 | 
            -
                      end
         | 
| 143 | 
            -
                    end
         | 
| 144 | 
            -
                  end
         | 
| 145 | 
            -
             | 
| 146 136 | 
             
                  def inspect
         | 
| 147 137 | 
             
                    "#<#{self.class.name}:0x#{self.object_id.to_s(16)}>"
         | 
| 148 138 | 
             
                  end
         | 
| 149 139 |  | 
| 150 140 | 
             
                  private
         | 
| 151 141 |  | 
| 152 | 
            -
                  SELECT_LOCAL | 
| 153 | 
            -
                  SELECT_PEERS | 
| 154 | 
            -
                  SELECT_KEYSPACES = Protocol::QueryRequest.new('SELECT * FROM system.schema_keyspaces', EMPTY_LIST, EMPTY_LIST, :one)
         | 
| 155 | 
            -
                  SELECT_TABLES    = Protocol::QueryRequest.new('SELECT * FROM system.schema_columnfamilies', EMPTY_LIST, EMPTY_LIST, :one)
         | 
| 156 | 
            -
                  SELECT_COLUMNS   = Protocol::QueryRequest.new('SELECT * FROM system.schema_columns', EMPTY_LIST, EMPTY_LIST, :one)
         | 
| 157 | 
            -
                  SELECT_TYPES     = Protocol::QueryRequest.new('SELECT * FROM system.schema_usertypes', EMPTY_LIST, EMPTY_LIST, :one)
         | 
| 142 | 
            +
                  SELECT_LOCAL  = Protocol::QueryRequest.new('SELECT rack, data_center, host_id, release_version, tokens, partitioner FROM system.local', EMPTY_LIST, EMPTY_LIST, :one)
         | 
| 143 | 
            +
                  SELECT_PEERS  = Protocol::QueryRequest.new('SELECT peer, rack, data_center, host_id, rpc_address, release_version, tokens FROM system.peers', EMPTY_LIST, EMPTY_LIST, :one)
         | 
| 158 144 |  | 
| 159 145 | 
             
                  def reconnect_async(schedule)
         | 
| 160 146 | 
             
                    timeout = schedule.next
         | 
| @@ -199,7 +185,7 @@ module Cassandra | |
| 199 185 | 
             
                      when Protocol::ReadyResponse
         | 
| 200 186 | 
             
                        nil
         | 
| 201 187 | 
             
                      when Protocol::ErrorResponse
         | 
| 202 | 
            -
                        raise r.to_error(VOID_STATEMENT)
         | 
| 188 | 
            +
                        raise r.to_error(nil, VOID_STATEMENT, VOID_OPTIONS, EMPTY_LIST, :one, 0)
         | 
| 203 189 | 
             
                      else
         | 
| 204 190 | 
             
                        raise Errors::InternalError, "Unexpected response #{r.inspect}"
         | 
| 205 191 | 
             
                      end
         | 
| @@ -215,7 +201,12 @@ module Cassandra | |
| 215 201 | 
             
                          when 'UP'
         | 
| 216 202 | 
             
                            address = event.address
         | 
| 217 203 |  | 
| 218 | 
            -
                             | 
| 204 | 
            +
                            if @registry.has_host?(address)
         | 
| 205 | 
            +
                              @registry.host_up(address)
         | 
| 206 | 
            +
                            else
         | 
| 207 | 
            +
                              refresh_host_async_maybe_retry(address)
         | 
| 208 | 
            +
                              refresh_maybe_retry(:schema)
         | 
| 209 | 
            +
                            end
         | 
| 219 210 | 
             
                          when 'DOWN'
         | 
| 220 211 | 
             
                            @registry.host_down(event.address)
         | 
| 221 212 | 
             
                          when 'NEW_NODE'
         | 
| @@ -223,11 +214,11 @@ module Cassandra | |
| 223 214 |  | 
| 224 215 | 
             
                            unless @registry.has_host?(address)
         | 
| 225 216 | 
             
                              refresh_host_async_maybe_retry(address)
         | 
| 226 | 
            -
                               | 
| 217 | 
            +
                              refresh_maybe_retry(:schema)
         | 
| 227 218 | 
             
                            end
         | 
| 228 219 | 
             
                          when 'REMOVED_NODE'
         | 
| 229 220 | 
             
                            @registry.host_lost(event.address)
         | 
| 230 | 
            -
                             | 
| 221 | 
            +
                            refresh_maybe_retry(:schema)
         | 
| 231 222 | 
             
                          end
         | 
| 232 223 | 
             
                        end
         | 
| 233 224 | 
             
                      end
         | 
| @@ -243,222 +234,117 @@ module Cassandra | |
| 243 234 |  | 
| 244 235 | 
             
                    return Ione::Future.failed(Errors::ClientError.new('Not connected')) if connection.nil?
         | 
| 245 236 |  | 
| 246 | 
            -
                     | 
| 247 | 
            -
             | 
| 248 | 
            -
                    columns   = send_select_request(connection, SELECT_COLUMNS)
         | 
| 249 | 
            -
             | 
| 250 | 
            -
                    if @connection_options.protocol_version > 2
         | 
| 251 | 
            -
                      types = send_select_request(connection, SELECT_TYPES)
         | 
| 252 | 
            -
                    else
         | 
| 253 | 
            -
                      types = Ione::Future.resolved(EMPTY_LIST)
         | 
| 254 | 
            -
                    end
         | 
| 255 | 
            -
             | 
| 256 | 
            -
                    Ione::Future.all(keyspaces, tables, columns, types).map do |(keyspaces, tables, columns, types)|
         | 
| 257 | 
            -
                      host = @registry.host(connection.host)
         | 
| 258 | 
            -
             | 
| 259 | 
            -
                      @schema.update_keyspaces(host, keyspaces, tables, columns, types)
         | 
| 237 | 
            +
                    @schema_fetcher.fetch(connection).map do |keyspaces|
         | 
| 238 | 
            +
                      @schema.replace(keyspaces)
         | 
| 260 239 | 
             
                      @metadata.rebuild_token_map
         | 
| 261 240 | 
             
                      @logger.info("Schema refreshed")
         | 
| 262 241 | 
             
                    end
         | 
| 263 242 | 
             
                  end
         | 
| 264 243 |  | 
| 265 | 
            -
                  def  | 
| 266 | 
            -
                     | 
| 267 | 
            -
                    @logger.info("Failed to refresh schema (#{error.class.name}: #{error.message}), retrying in #{timeout}")
         | 
| 244 | 
            +
                  def refresh_keyspace_async(keyspace_name)
         | 
| 245 | 
            +
                    connection = @connection
         | 
| 268 246 |  | 
| 269 | 
            -
                     | 
| 270 | 
            -
                    timer.flat_map do
         | 
| 271 | 
            -
                      refresh_schema_async.fallback do |e|
         | 
| 272 | 
            -
                        case e
         | 
| 273 | 
            -
                        when Errors::HostError
         | 
| 274 | 
            -
                          refresh_schema_async_retry(e, schedule)
         | 
| 275 | 
            -
                        else
         | 
| 276 | 
            -
                          connection = @connection
         | 
| 277 | 
            -
                          connection && connection.close(e)
         | 
| 247 | 
            +
                    return Ione::Future.failed(Errors::ClientError.new('Not connected')) if connection.nil?
         | 
| 278 248 |  | 
| 279 | 
            -
             | 
| 280 | 
            -
                        end
         | 
| 281 | 
            -
                      end
         | 
| 282 | 
            -
                    end
         | 
| 283 | 
            -
                  end
         | 
| 249 | 
            +
                    @logger.info("Refreshing keyspace \"#{keyspace_name}\"")
         | 
| 284 250 |  | 
| 285 | 
            -
             | 
| 286 | 
            -
             | 
| 287 | 
            -
             | 
| 288 | 
            -
                      when Errors::HostError
         | 
| 289 | 
            -
                        refresh_keyspace_async_retry(keyspace, e, @reconnection_policy.schedule)
         | 
| 251 | 
            +
                    @schema_fetcher.fetch_keyspace(connection, keyspace_name).map do |keyspace|
         | 
| 252 | 
            +
                      if keyspace
         | 
| 253 | 
            +
                        @schema.replace_keyspace(keyspace)
         | 
| 290 254 | 
             
                      else
         | 
| 291 | 
            -
                         | 
| 292 | 
            -
                        connection && connection.close(e)
         | 
| 293 | 
            -
             | 
| 294 | 
            -
                        Ione::Future.failed(e)
         | 
| 255 | 
            +
                        @schema.delete_keyspace(keyspace_name)
         | 
| 295 256 | 
             
                      end
         | 
| 296 | 
            -
                    end
         | 
| 297 | 
            -
                  end
         | 
| 298 257 |  | 
| 299 | 
            -
             | 
| 300 | 
            -
                    timeout = schedule.next
         | 
| 301 | 
            -
                    @logger.info("Failed to refresh keyspace #{keyspace} (#{error.class.name}: #{error.message}), retrying in #{timeout}")
         | 
| 302 | 
            -
             | 
| 303 | 
            -
                    timer = @io_reactor.schedule_timer(timeout)
         | 
| 304 | 
            -
                    timer.flat_map do
         | 
| 305 | 
            -
                      refresh_keyspace_async(keyspace).fallback do |e|
         | 
| 306 | 
            -
                        case e
         | 
| 307 | 
            -
                        when Errors::HostError
         | 
| 308 | 
            -
                          refresh_keyspace_async_retry(keyspace, e, schedule)
         | 
| 309 | 
            -
                        else
         | 
| 310 | 
            -
                          connection = @connection
         | 
| 311 | 
            -
                          connection && connection.close(e)
         | 
| 312 | 
            -
             | 
| 313 | 
            -
                          Ione::Future.failed(e)
         | 
| 314 | 
            -
                        end
         | 
| 315 | 
            -
                      end
         | 
| 258 | 
            +
                      @logger.info("Refreshed keyspace \"#{keyspace_name}\"")
         | 
| 316 259 | 
             
                    end
         | 
| 317 260 | 
             
                  end
         | 
| 318 261 |  | 
| 319 | 
            -
                  def  | 
| 262 | 
            +
                  def refresh_table_async(keyspace_name, table_name)
         | 
| 320 263 | 
             
                    connection = @connection
         | 
| 321 264 |  | 
| 322 265 | 
             
                    return Ione::Future.failed(Errors::ClientError.new('Not connected')) if connection.nil?
         | 
| 323 266 |  | 
| 324 | 
            -
                     | 
| 325 | 
            -
                    tables    = send_select_request(connection, Protocol::QueryRequest.new("SELECT * FROM system.schema_columnfamilies WHERE keyspace_name = '%s'" % keyspace, EMPTY_LIST, EMPTY_LIST, :one))
         | 
| 326 | 
            -
                    columns   = send_select_request(connection, Protocol::QueryRequest.new("SELECT * FROM system.schema_columns WHERE keyspace_name = '%s'" % keyspace, EMPTY_LIST, EMPTY_LIST, :one))
         | 
| 327 | 
            -
             | 
| 328 | 
            -
                    if @connection_options.protocol_version > 2
         | 
| 329 | 
            -
                      types = send_select_request(connection, Protocol::QueryRequest.new("SELECT * FROM system.schema_usertypes WHERE keyspace_name = '%s'" % keyspace, EMPTY_LIST, EMPTY_LIST, :one))
         | 
| 330 | 
            -
                    else
         | 
| 331 | 
            -
                      types = Ione::Future.resolved(EMPTY_LIST)
         | 
| 332 | 
            -
                    end
         | 
| 333 | 
            -
             | 
| 334 | 
            -
                    Ione::Future.all(keyspaces, tables, columns, types).map do |(keyspaces, tables, columns, types)|
         | 
| 335 | 
            -
                      host = @registry.host(connection.host)
         | 
| 267 | 
            +
                    @logger.info("Refreshing table \"#{keyspace_name}.#{table_name}\"")
         | 
| 336 268 |  | 
| 337 | 
            -
             | 
| 338 | 
            -
             | 
| 269 | 
            +
                    @schema_fetcher.fetch_table(connection, keyspace_name, table_name).map do |table|
         | 
| 270 | 
            +
                      if table
         | 
| 271 | 
            +
                        @schema.replace_table(table)
         | 
| 339 272 | 
             
                      else
         | 
| 340 | 
            -
                        @schema. | 
| 341 | 
            -
                      end
         | 
| 342 | 
            -
                    end
         | 
| 343 | 
            -
                  end
         | 
| 344 | 
            -
             | 
| 345 | 
            -
                  def refresh_table_async_maybe_retry(keyspace, table)
         | 
| 346 | 
            -
                    refresh_table_async(keyspace, table).fallback do |e|
         | 
| 347 | 
            -
                      case e
         | 
| 348 | 
            -
                      when Errors::HostError
         | 
| 349 | 
            -
                        refresh_keyspace_async_retry(keyspace, e, @reconnection_policy.schedule)
         | 
| 350 | 
            -
                      else
         | 
| 351 | 
            -
                        connection = @connection
         | 
| 352 | 
            -
                        connection && connection.close(e)
         | 
| 353 | 
            -
             | 
| 354 | 
            -
                        Ione::Future.failed(e)
         | 
| 273 | 
            +
                        @schema.delete_table(keyspace_name, table_name)
         | 
| 355 274 | 
             
                      end
         | 
| 356 | 
            -
                    end
         | 
| 357 | 
            -
                  end
         | 
| 358 | 
            -
             | 
| 359 | 
            -
                  def refresh_table_async_retry(keyspace, table, error, schedule)
         | 
| 360 | 
            -
                    timeout = schedule.next
         | 
| 361 | 
            -
                    @logger.info("Failed to refresh keyspace #{keyspace} (#{error.class.name}: #{error.message}), retrying in #{timeout}")
         | 
| 362 | 
            -
             | 
| 363 | 
            -
                    timer = @io_reactor.schedule_timer(timeout)
         | 
| 364 | 
            -
                    timer.flat_map do
         | 
| 365 | 
            -
                      refresh_keyspace_async(keyspace).fallback do |e|
         | 
| 366 | 
            -
                        case e
         | 
| 367 | 
            -
                        when Errors::HostError
         | 
| 368 | 
            -
                          refresh_keyspace_async_retry(keyspace, e, schedule)
         | 
| 369 | 
            -
                        else
         | 
| 370 | 
            -
                          connection = @connection
         | 
| 371 | 
            -
                          connection && connection.close(e)
         | 
| 372 275 |  | 
| 373 | 
            -
             | 
| 374 | 
            -
                        end
         | 
| 375 | 
            -
                      end
         | 
| 276 | 
            +
                      @logger.info("Refreshed table \"#{keyspace_name}.#{table_name}\"")
         | 
| 376 277 | 
             
                    end
         | 
| 377 278 | 
             
                  end
         | 
| 378 279 |  | 
| 379 | 
            -
                  def  | 
| 280 | 
            +
                  def refresh_type_async(keyspace_name, type_name)
         | 
| 380 281 | 
             
                    connection = @connection
         | 
| 381 282 |  | 
| 382 283 | 
             
                    return Ione::Future.failed(Errors::ClientError.new('Not connected')) if connection.nil?
         | 
| 383 284 |  | 
| 384 | 
            -
                     | 
| 385 | 
            -
                    tables   = send_select_request(connection, Protocol::QueryRequest.new("SELECT * FROM system.schema_columnfamilies WHERE keyspace_name = '%s' AND columnfamily_name = '%s'" % params, EMPTY_LIST, EMPTY_LIST, :one))
         | 
| 386 | 
            -
                    columns  = send_select_request(connection, Protocol::QueryRequest.new("SELECT * FROM system.schema_columns WHERE keyspace_name = '%s' AND columnfamily_name = '%s'" % params, EMPTY_LIST, EMPTY_LIST, :one))
         | 
| 285 | 
            +
                    @logger.info("Refreshing user-defined type \"#{keyspace_name}.#{type_name}\"")
         | 
| 387 286 |  | 
| 388 | 
            -
                     | 
| 389 | 
            -
                       | 
| 390 | 
            -
             | 
| 391 | 
            -
                      if tables.empty?
         | 
| 392 | 
            -
                        @schema.delete_table(keyspace, table)
         | 
| 287 | 
            +
                    @schema_fetcher.fetch_type(connection, keyspace_name, type_name).map do |type|
         | 
| 288 | 
            +
                      if type
         | 
| 289 | 
            +
                        @schema.replace_type(type)
         | 
| 393 290 | 
             
                      else
         | 
| 394 | 
            -
                        @schema. | 
| 291 | 
            +
                        @schema.delete_type(keyspace_name, type_name)
         | 
| 395 292 | 
             
                      end
         | 
| 396 | 
            -
                    end
         | 
| 397 | 
            -
                  end
         | 
| 398 293 |  | 
| 399 | 
            -
             | 
| 400 | 
            -
                    refresh_type_async(keyspace, type).fallback do |e|
         | 
| 401 | 
            -
                      case e
         | 
| 402 | 
            -
                      when Errors::HostError
         | 
| 403 | 
            -
                        refresh_keyspace_async_retry(keyspace, e, @reconnection_policy.schedule)
         | 
| 404 | 
            -
                      else
         | 
| 405 | 
            -
                        connection = @connection
         | 
| 406 | 
            -
                        connection && connection.close(e)
         | 
| 407 | 
            -
             | 
| 408 | 
            -
                        Ione::Future.failed(e)
         | 
| 409 | 
            -
                      end
         | 
| 294 | 
            +
                      @logger.info("Refreshed user-defined type \"#{keyspace_name}.#{type_name}\"")
         | 
| 410 295 | 
             
                    end
         | 
| 411 296 | 
             
                  end
         | 
| 412 297 |  | 
| 413 | 
            -
                  def  | 
| 414 | 
            -
                     | 
| 415 | 
            -
                    @logger.info("Failed to refresh type #{keyspace}.#{type} (#{error.class.name}: #{error.message}), retrying in #{timeout}")
         | 
| 298 | 
            +
                  def refresh_function_async(keyspace_name, function_name, function_args)
         | 
| 299 | 
            +
                    connection = @connection
         | 
| 416 300 |  | 
| 417 | 
            -
                     | 
| 418 | 
            -
                    timer.flat_map do
         | 
| 419 | 
            -
                      refresh_keyspace_async(keyspace).fallback do |e|
         | 
| 420 | 
            -
                        case e
         | 
| 421 | 
            -
                        when Errors::HostError
         | 
| 422 | 
            -
                          refresh_keyspace_async_retry(keyspace, e, schedule)
         | 
| 423 | 
            -
                        else
         | 
| 424 | 
            -
                          connection = @connection
         | 
| 425 | 
            -
                          connection && connection.close(e)
         | 
| 301 | 
            +
                    return Ione::Future.failed(Errors::ClientError.new('Not connected')) if connection.nil?
         | 
| 426 302 |  | 
| 427 | 
            -
             | 
| 428 | 
            -
             | 
| 303 | 
            +
                    @logger.info("Refreshing user-defined function \"#{keyspace_name}.#{function_name}\"")
         | 
| 304 | 
            +
             | 
| 305 | 
            +
                    # function_args is an array of string, and we need an array of parsed types.
         | 
| 306 | 
            +
                    parsed_function_args = @schema_fetcher.parse_argument_types(connection, keyspace_name, function_args)
         | 
| 307 | 
            +
                    @schema_fetcher.fetch_function(connection, keyspace_name, function_name, parsed_function_args).map do |function|
         | 
| 308 | 
            +
                      if function
         | 
| 309 | 
            +
                        @schema.replace_function(function)
         | 
| 310 | 
            +
                      else
         | 
| 311 | 
            +
                        @schema.delete_function(keyspace_name, function_name, parsed_function_args)
         | 
| 429 312 | 
             
                      end
         | 
| 313 | 
            +
             | 
| 314 | 
            +
                      @logger.info("Refreshed user-defined function \"#{keyspace_name}.#{function_name}(#{function_args.join(',')})\"")
         | 
| 430 315 | 
             
                    end
         | 
| 431 316 | 
             
                  end
         | 
| 432 317 |  | 
| 433 | 
            -
                  def  | 
| 318 | 
            +
                  def refresh_aggregate_async(keyspace_name, aggregate_name, aggregate_args)
         | 
| 434 319 | 
             
                    connection = @connection
         | 
| 435 320 |  | 
| 436 321 | 
             
                    return Ione::Future.failed(Errors::ClientError.new('Not connected')) if connection.nil?
         | 
| 437 322 |  | 
| 438 | 
            -
                     | 
| 439 | 
            -
                    types    = send_select_request(connection, Protocol::QueryRequest.new("SELECT * FROM system.schema_usertypes WHERE keyspace_name = '%s' AND type_name = '%s'" % params, EMPTY_LIST, EMPTY_LIST, :one))
         | 
| 440 | 
            -
             | 
| 441 | 
            -
                    types.map do |types|
         | 
| 442 | 
            -
                      host = @registry.host(connection.host)
         | 
| 323 | 
            +
                    @logger.info("Refreshing user-defined aggregate \"#{keyspace_name}.#{aggregate_name}\"")
         | 
| 443 324 |  | 
| 444 | 
            -
             | 
| 445 | 
            -
             | 
| 325 | 
            +
                    # aggregate_args is an array of string, and we need an array of parsed types.
         | 
| 326 | 
            +
                    parsed_aggregate_args = @schema_fetcher.parse_argument_types(connection, keyspace_name, aggregate_args)
         | 
| 327 | 
            +
                    @schema_fetcher.fetch_aggregate(connection, keyspace_name, aggregate_name, parsed_aggregate_args).map do |aggregate|
         | 
| 328 | 
            +
                      if aggregate
         | 
| 329 | 
            +
                        @schema.replace_aggregate(aggregate)
         | 
| 446 330 | 
             
                      else
         | 
| 447 | 
            -
                        @schema. | 
| 331 | 
            +
                        @schema.delete_aggregate(keyspace_name, aggregate_name, parsed_aggregate_args)
         | 
| 448 332 | 
             
                      end
         | 
| 333 | 
            +
             | 
| 334 | 
            +
                      @logger.info("Refreshed user-defined aggregate \"#{keyspace_name}.#{aggregate_name}(#{aggregate_args.join(',')})\"")
         | 
| 449 335 | 
             
                    end
         | 
| 450 336 | 
             
                  end
         | 
| 451 337 |  | 
| 452 | 
            -
                  def  | 
| 338 | 
            +
                  def refresh_peers_async_maybe_retry
         | 
| 453 339 | 
             
                    synchronize do
         | 
| 454 340 | 
             
                      return Ione::Future.resolved if @refreshing_hosts
         | 
| 455 341 | 
             
                      @refreshing_hosts = true
         | 
| 456 342 | 
             
                    end
         | 
| 457 343 |  | 
| 458 | 
            -
                     | 
| 344 | 
            +
                    refresh_peers_async.fallback do |e|
         | 
| 459 345 | 
             
                      case e
         | 
| 460 | 
            -
                      when Errors::HostError
         | 
| 461 | 
            -
                         | 
| 346 | 
            +
                      when Errors::HostError, Errors::TimeoutError
         | 
| 347 | 
            +
                        refresh_peers_async_retry(e, @reconnection_policy.schedule)
         | 
| 462 348 | 
             
                      else
         | 
| 463 349 | 
             
                        connection = @connection
         | 
| 464 350 | 
             
                        connection && connection.close(e)
         | 
| @@ -472,16 +358,16 @@ module Cassandra | |
| 472 358 | 
             
                    end
         | 
| 473 359 | 
             
                  end
         | 
| 474 360 |  | 
| 475 | 
            -
                  def  | 
| 361 | 
            +
                  def refresh_peers_async_retry(error, schedule)
         | 
| 476 362 | 
             
                    timeout = schedule.next
         | 
| 477 363 | 
             
                    @logger.info("Failed to refresh hosts (#{error.class.name}: #{error.message}), retrying in #{timeout}")
         | 
| 478 364 |  | 
| 479 365 | 
             
                    timer = @io_reactor.schedule_timer(timeout)
         | 
| 480 366 | 
             
                    timer.flat_map do
         | 
| 481 | 
            -
                       | 
| 367 | 
            +
                      refresh_peers_async.fallback do |e|
         | 
| 482 368 | 
             
                        case e
         | 
| 483 | 
            -
                        when Errors::HostError
         | 
| 484 | 
            -
                           | 
| 369 | 
            +
                        when Errors::HostError, Errors::TimeoutError
         | 
| 370 | 
            +
                          refresh_peers_async_retry(e, schedule)
         | 
| 485 371 | 
             
                        else
         | 
| 486 372 | 
             
                          connection = @connection
         | 
| 487 373 | 
             
                          connection && connection.close(e)
         | 
| @@ -492,38 +378,55 @@ module Cassandra | |
| 492 378 | 
             
                    end
         | 
| 493 379 | 
             
                  end
         | 
| 494 380 |  | 
| 495 | 
            -
                  def  | 
| 381 | 
            +
                  def refresh_peers_async
         | 
| 496 382 | 
             
                    connection = @connection
         | 
| 497 383 |  | 
| 498 384 | 
             
                    return Ione::Future.failed(Errors::ClientError.new('Not connected')) if connection.nil?
         | 
| 499 385 |  | 
| 500 | 
            -
                     | 
| 501 | 
            -
                    peers = send_select_request(connection, SELECT_PEERS)
         | 
| 386 | 
            +
                    @logger.info("Refreshing peers metadata")
         | 
| 502 387 |  | 
| 503 | 
            -
                     | 
| 388 | 
            +
                    send_select_request(connection, SELECT_PEERS).map do |peers|
         | 
| 504 389 | 
             
                      @logger.debug("#{peers.size} peer(s) found")
         | 
| 505 390 |  | 
| 506 391 | 
             
                      ips = ::Set.new
         | 
| 507 392 |  | 
| 508 | 
            -
                      unless local.empty?
         | 
| 509 | 
            -
                        ips << ip = IPAddr.new(connection.host)
         | 
| 510 | 
            -
                        data = local.first
         | 
| 511 | 
            -
                        @registry.host_found(ip, data)
         | 
| 512 | 
            -
                        @metadata.update(data)
         | 
| 513 | 
            -
                      end
         | 
| 514 | 
            -
             | 
| 515 393 | 
             
                      peers.shuffle!
         | 
| 516 394 | 
             
                      peers.each do |data|
         | 
| 517 | 
            -
                        ip = peer_ip(data | 
| 395 | 
            +
                        ip = peer_ip(data)
         | 
| 518 396 | 
             
                        next unless ip
         | 
| 519 397 | 
             
                        ips << ip
         | 
| 520 398 | 
             
                        @registry.host_found(ip, data)
         | 
| 521 399 | 
             
                      end
         | 
| 522 400 |  | 
| 523 401 | 
             
                      @registry.each_host do |host|
         | 
| 402 | 
            +
                        next if host.ip == connection.host
         | 
| 524 403 | 
             
                        @registry.host_lost(host.ip) unless ips.include?(host.ip)
         | 
| 525 404 | 
             
                      end
         | 
| 526 405 |  | 
| 406 | 
            +
                      @logger.info("Refreshed peers metadata")
         | 
| 407 | 
            +
             | 
| 408 | 
            +
                      nil
         | 
| 409 | 
            +
                    end
         | 
| 410 | 
            +
                  end
         | 
| 411 | 
            +
             | 
| 412 | 
            +
                  def refresh_metadata_async
         | 
| 413 | 
            +
                    connection = @connection
         | 
| 414 | 
            +
             | 
| 415 | 
            +
                    return Ione::Future.failed(Errors::ClientError.new('Not connected')) if connection.nil?
         | 
| 416 | 
            +
             | 
| 417 | 
            +
                    @logger.info("Refreshing connected host's metadata")
         | 
| 418 | 
            +
             | 
| 419 | 
            +
                    send_select_request(connection, SELECT_LOCAL).map do |local|
         | 
| 420 | 
            +
                      if local.empty?
         | 
| 421 | 
            +
                        raise Errors::InternalError, "Unable to fetch connected host's metadata"
         | 
| 422 | 
            +
                      else
         | 
| 423 | 
            +
                        data = local.first
         | 
| 424 | 
            +
                        @registry.host_found(IPAddr.new(connection.host), data)
         | 
| 425 | 
            +
                        @metadata.update(data)
         | 
| 426 | 
            +
                      end
         | 
| 427 | 
            +
             | 
| 428 | 
            +
                      @logger.info("Refreshed connected host's metadata")
         | 
| 429 | 
            +
             | 
| 527 430 | 
             
                      nil
         | 
| 528 431 | 
             
                    end
         | 
| 529 432 | 
             
                  end
         | 
| @@ -555,16 +458,16 @@ module Cassandra | |
| 555 458 | 
             
                    end
         | 
| 556 459 | 
             
                  end
         | 
| 557 460 |  | 
| 558 | 
            -
                  def refresh_host_async_maybe_retry( | 
| 461 | 
            +
                  def refresh_host_async_maybe_retry(address)
         | 
| 559 462 | 
             
                    synchronize do
         | 
| 560 | 
            -
                      return Ione::Future.resolved if @refreshing_hosts || @refreshing_host[ | 
| 561 | 
            -
                      @refreshing_host[ | 
| 463 | 
            +
                      return Ione::Future.resolved if @refreshing_hosts || @refreshing_host[address]
         | 
| 464 | 
            +
                      @refreshing_host[address] = true
         | 
| 562 465 | 
             
                    end
         | 
| 563 466 |  | 
| 564 | 
            -
                    refresh_host_async( | 
| 467 | 
            +
                    refresh_host_async(address).fallback do |e|
         | 
| 565 468 | 
             
                      case e
         | 
| 566 | 
            -
                      when Errors::HostError
         | 
| 567 | 
            -
                        refresh_host_async_retry( | 
| 469 | 
            +
                      when Errors::HostError, Errors::TimeoutError
         | 
| 470 | 
            +
                        refresh_host_async_retry(address, e, @reconnection_policy.schedule)
         | 
| 568 471 | 
             
                      else
         | 
| 569 472 | 
             
                        connection = @connection
         | 
| 570 473 | 
             
                        connection && connection.close(e)
         | 
| @@ -573,21 +476,21 @@ module Cassandra | |
| 573 476 | 
             
                      end
         | 
| 574 477 | 
             
                    end.map do
         | 
| 575 478 | 
             
                      synchronize do
         | 
| 576 | 
            -
                        @refreshing_host.delete( | 
| 479 | 
            +
                        @refreshing_host.delete(address)
         | 
| 577 480 | 
             
                      end
         | 
| 578 481 | 
             
                    end
         | 
| 579 482 | 
             
                  end
         | 
| 580 483 |  | 
| 581 | 
            -
                  def refresh_host_async_retry( | 
| 484 | 
            +
                  def refresh_host_async_retry(address, error, schedule)
         | 
| 582 485 | 
             
                    timeout = schedule.next
         | 
| 583 | 
            -
                    @logger.info("Failed to refresh host #{ | 
| 486 | 
            +
                    @logger.info("Failed to refresh host #{address.to_s} (#{error.class.name}: #{error.message}), retrying in #{timeout}")
         | 
| 584 487 |  | 
| 585 488 | 
             
                    timer = @io_reactor.schedule_timer(timeout)
         | 
| 586 489 | 
             
                    timer.flat_map do
         | 
| 587 | 
            -
                      refresh_host_async( | 
| 490 | 
            +
                      refresh_host_async(address).fallback do |e|
         | 
| 588 491 | 
             
                        case e
         | 
| 589 | 
            -
                        when Errors::HostError
         | 
| 590 | 
            -
                          refresh_host_async_retry( | 
| 492 | 
            +
                        when Errors::HostError, Errors::TimeoutError
         | 
| 493 | 
            +
                          refresh_host_async_retry(address, e, schedule)
         | 
| 591 494 | 
             
                        else
         | 
| 592 495 | 
             
                          connection = @connection
         | 
| 593 496 | 
             
                          connection && connection.close(e)
         | 
| @@ -604,19 +507,26 @@ module Cassandra | |
| 604 507 |  | 
| 605 508 | 
             
                    ip = address.to_s
         | 
| 606 509 |  | 
| 510 | 
            +
                    @logger.info("Refreshing host metadata: #{ip}")
         | 
| 511 | 
            +
             | 
| 607 512 | 
             
                    if ip == connection.host
         | 
| 608 513 | 
             
                      request = SELECT_LOCAL
         | 
| 609 514 | 
             
                    else
         | 
| 610 | 
            -
                      request = Protocol::QueryRequest.new("SELECT rack, data_center, host_id, rpc_address, release_version, tokens FROM system.peers WHERE peer = '%s'" %  | 
| 515 | 
            +
                      request = Protocol::QueryRequest.new("SELECT rack, data_center, host_id, rpc_address, release_version, tokens FROM system.peers WHERE peer = '%s'" % ip, EMPTY_LIST, EMPTY_LIST, :one)
         | 
| 611 516 | 
             
                    end
         | 
| 612 517 |  | 
| 613 518 | 
             
                    send_select_request(connection, request).map do |rows|
         | 
| 614 | 
            -
                       | 
| 519 | 
            +
                      if rows.empty?
         | 
| 520 | 
            +
                        raise Errors::InternalError, "Unable to find host metadata: #{ip}"
         | 
| 521 | 
            +
                      else
         | 
| 522 | 
            +
                        @logger.info("Refreshed host metadata: #{ip}")
         | 
| 615 523 | 
             
                        @registry.host_found(address, rows.first)
         | 
| 616 524 | 
             
                      end
         | 
| 617 525 |  | 
| 618 526 | 
             
                      self
         | 
| 619 527 | 
             
                    end
         | 
| 528 | 
            +
                  rescue => e
         | 
| 529 | 
            +
                    @logger.error("Refreshing host metadata failed (#{e.class.name}: #{e.message})")
         | 
| 620 530 | 
             
                  end
         | 
| 621 531 |  | 
| 622 532 | 
             
                  def connect_to_first_available(plan, errors = nil)
         | 
| @@ -671,15 +581,16 @@ Control connection failed and is unlikely to recover. | |
| 671 581 | 
             
                        end
         | 
| 672 582 | 
             
                      end
         | 
| 673 583 |  | 
| 674 | 
            -
                       | 
| 584 | 
            +
                      refresh_maybe_retry(:metadata)
         | 
| 675 585 | 
             
                    end
         | 
| 676 | 
            -
                    f = f.flat_map {  | 
| 677 | 
            -
                    f = f.flat_map {  | 
| 586 | 
            +
                    f = f.flat_map { register_async }
         | 
| 587 | 
            +
                    f = f.flat_map { refresh_peers_async_maybe_retry }
         | 
| 588 | 
            +
                    f = f.flat_map { refresh_maybe_retry(:schema) } if @connection_options.synchronize_schema?
         | 
| 678 589 | 
             
                    f = f.fallback do |error|
         | 
| 679 590 | 
             
                      @logger.debug("Connection to #{host.ip} failed (#{error.class.name}: #{error.message})")
         | 
| 680 591 |  | 
| 681 592 | 
             
                      case error
         | 
| 682 | 
            -
                      when Errors::HostError
         | 
| 593 | 
            +
                      when Errors::HostError, Errors::TimeoutError
         | 
| 683 594 | 
             
                        errors ||= {}
         | 
| 684 595 | 
             
                        errors[host] = error
         | 
| 685 596 | 
             
                        connect_to_first_available(plan, errors)
         | 
| @@ -699,38 +610,23 @@ Control connection failed and is unlikely to recover. | |
| 699 610 | 
             
                    @connector.connect(host)
         | 
| 700 611 | 
             
                  end
         | 
| 701 612 |  | 
| 702 | 
            -
                  def peer_ip(data | 
| 703 | 
            -
                     | 
| 704 | 
            -
             | 
| 705 | 
            -
                    return nil unless peer && data['host_id'] && data['data_center'] && data['rack'] && data['tokens']
         | 
| 706 | 
            -
             | 
| 707 | 
            -
                    rpc_address = data['rpc_address']
         | 
| 708 | 
            -
             | 
| 709 | 
            -
                    if rpc_address.nil?
         | 
| 710 | 
            -
                      @logger.info("The system.peers row for '#{data['peer']}' has no rpc_address. This is likely " +
         | 
| 711 | 
            -
                                       'a gossip or snitch issue. This host will be ignored.')
         | 
| 712 | 
            -
                      return nil
         | 
| 713 | 
            -
                    end
         | 
| 714 | 
            -
             | 
| 715 | 
            -
                    if peer == host_address || rpc_address == host_address
         | 
| 716 | 
            -
                      # Some DSE versions were inserting a line for the local node in peers (with mostly null values).
         | 
| 717 | 
            -
                      # This has been fixed, but if we detect that's the case, ignore it as it's not really a big deal.
         | 
| 718 | 
            -
             | 
| 719 | 
            -
                      @logger.debug("System.peers on node #{host_address} has a line for itself. This is not normal but is a " +
         | 
| 720 | 
            -
                                        'known problem of some DSE versions. Ignoring the entry.')
         | 
| 721 | 
            -
                      return nil
         | 
| 722 | 
            -
                    end
         | 
| 723 | 
            -
             | 
| 724 | 
            -
                    ip = rpc_address
         | 
| 725 | 
            -
                    ip = peer if ip == '0.0.0.0'
         | 
| 613 | 
            +
                  def peer_ip(data)
         | 
| 614 | 
            +
                    ip = data['rpc_address']
         | 
| 615 | 
            +
                    ip = data['peer'] if ip == '0.0.0.0'
         | 
| 726 616 |  | 
| 727 617 | 
             
                    @address_resolver.resolve(ip)
         | 
| 728 618 | 
             
                  end
         | 
| 729 619 |  | 
| 730 620 | 
             
                  def process_schema_changes(schema_changes)
         | 
| 731 | 
            -
                    refresh_keyspaces | 
| 732 | 
            -
                    refresh_tables | 
| 733 | 
            -
                    refresh_types | 
| 621 | 
            +
                    refresh_keyspaces  = ::Hash.new
         | 
| 622 | 
            +
                    refresh_tables     = ::Hash.new
         | 
| 623 | 
            +
                    refresh_types      = ::Hash.new
         | 
| 624 | 
            +
             | 
| 625 | 
            +
                    # This hash is of the form <keyspace, [Change (for function changes)]>
         | 
| 626 | 
            +
                    refresh_functions  = ::Hash.new
         | 
| 627 | 
            +
             | 
| 628 | 
            +
                    # This hash is of the form <keyspace, [Change (for aggregate changes)]>
         | 
| 629 | 
            +
                    refresh_aggregates = ::Hash.new
         | 
| 734 630 |  | 
| 735 631 | 
             
                    schema_changes.each do |change|
         | 
| 736 632 | 
             
                      keyspace = change.keyspace
         | 
| @@ -741,37 +637,91 @@ Control connection failed and is unlikely to recover. | |
| 741 637 | 
             
                      when Protocol::Constants::SCHEMA_CHANGE_TARGET_KEYSPACE
         | 
| 742 638 | 
             
                        refresh_tables.delete(keyspace)
         | 
| 743 639 | 
             
                        refresh_types.delete(keyspace)
         | 
| 640 | 
            +
                        refresh_functions.delete(keyspace)
         | 
| 641 | 
            +
                        refresh_aggregates.delete(keyspace)
         | 
| 744 642 | 
             
                        refresh_keyspaces[keyspace] = true
         | 
| 745 643 | 
             
                      when Protocol::Constants::SCHEMA_CHANGE_TARGET_TABLE
         | 
| 746 644 | 
             
                        tables = refresh_tables[keyspace] ||= ::Hash.new
         | 
| 747 | 
            -
                        tables[change. | 
| 645 | 
            +
                        tables[change.name] = true
         | 
| 748 646 | 
             
                      when Protocol::Constants::SCHEMA_CHANGE_TARGET_UDT
         | 
| 749 647 | 
             
                        types = refresh_types[keyspace] ||= ::Hash.new
         | 
| 750 | 
            -
                        types[change. | 
| 648 | 
            +
                        types[change.name] = true
         | 
| 649 | 
            +
                      when Protocol::Constants::SCHEMA_CHANGE_TARGET_FUNCTION
         | 
| 650 | 
            +
                        functions = refresh_functions[keyspace] ||= []
         | 
| 651 | 
            +
                        functions << change
         | 
| 652 | 
            +
                      when Protocol::Constants::SCHEMA_CHANGE_TARGET_AGGREGATE
         | 
| 653 | 
            +
                        aggregates = refresh_aggregates[keyspace] ||= []
         | 
| 654 | 
            +
                        aggregates << change
         | 
| 751 655 | 
             
                      end
         | 
| 752 656 | 
             
                    end
         | 
| 753 657 |  | 
| 754 658 | 
             
                    futures = ::Array.new
         | 
| 755 659 |  | 
| 756 660 | 
             
                    refresh_keyspaces.each_key do |keyspace|
         | 
| 757 | 
            -
                      futures <<  | 
| 661 | 
            +
                      futures << refresh_maybe_retry(:keyspace, keyspace)
         | 
| 758 662 | 
             
                    end
         | 
| 759 663 |  | 
| 760 664 | 
             
                    refresh_tables.each do |(keyspace, tables)|
         | 
| 761 665 | 
             
                      tables.each_key do |table|
         | 
| 762 | 
            -
                        futures <<  | 
| 666 | 
            +
                        futures << refresh_maybe_retry(:table, keyspace, table)
         | 
| 763 667 | 
             
                      end
         | 
| 764 668 | 
             
                    end
         | 
| 765 669 |  | 
| 766 670 | 
             
                    refresh_types.each do |(keyspace, types)|
         | 
| 767 671 | 
             
                      types.each_key do |type|
         | 
| 768 | 
            -
                        futures <<  | 
| 672 | 
            +
                        futures << refresh_maybe_retry(:type, keyspace, type)
         | 
| 673 | 
            +
                      end
         | 
| 674 | 
            +
                    end
         | 
| 675 | 
            +
             | 
| 676 | 
            +
                    refresh_functions.each do |(keyspace, function_changes)|
         | 
| 677 | 
            +
                      function_changes.each do |change|
         | 
| 678 | 
            +
                        futures << refresh_maybe_retry(:function, keyspace, change.name, change.arguments)
         | 
| 679 | 
            +
                      end
         | 
| 680 | 
            +
                    end
         | 
| 681 | 
            +
             | 
| 682 | 
            +
                    refresh_aggregates.each do |(keyspace, aggregate_changes)|
         | 
| 683 | 
            +
                      aggregate_changes.each do |change|
         | 
| 684 | 
            +
                        futures << refresh_maybe_retry(:aggregate, keyspace, change.name, change.arguments)
         | 
| 769 685 | 
             
                      end
         | 
| 770 686 | 
             
                    end
         | 
| 771 687 |  | 
| 772 688 | 
             
                    Ione::Future.all(*futures)
         | 
| 773 689 | 
             
                  end
         | 
| 774 690 |  | 
| 691 | 
            +
                  def refresh_maybe_retry(what, *args)
         | 
| 692 | 
            +
                    send(:"refresh_#{what}_async", *args).fallback do |e|
         | 
| 693 | 
            +
                      case e
         | 
| 694 | 
            +
                      when Errors::HostError, Errors::TimeoutError
         | 
| 695 | 
            +
                        refresh_retry(what, e, @reconnection_policy.schedule, *args)
         | 
| 696 | 
            +
                      else
         | 
| 697 | 
            +
                        connection = @connection
         | 
| 698 | 
            +
                        connection && connection.close(e)
         | 
| 699 | 
            +
             | 
| 700 | 
            +
                        Ione::Future.failed(e)
         | 
| 701 | 
            +
                      end
         | 
| 702 | 
            +
                    end
         | 
| 703 | 
            +
                  end
         | 
| 704 | 
            +
             | 
| 705 | 
            +
                  def refresh_retry(what, error, schedule, *args)
         | 
| 706 | 
            +
                    timeout = schedule.next
         | 
| 707 | 
            +
                    @logger.info("Failed to refresh #{what} #{args.inspect} (#{error.class.name}: #{error.message}), retrying in #{timeout}")
         | 
| 708 | 
            +
             | 
| 709 | 
            +
                    timer = @io_reactor.schedule_timer(timeout)
         | 
| 710 | 
            +
                    timer.flat_map do
         | 
| 711 | 
            +
                      send(:"refresh_#{what}_async", *args).fallback do |e|
         | 
| 712 | 
            +
                        case e
         | 
| 713 | 
            +
                        when Errors::HostError, Errors::TimeoutError
         | 
| 714 | 
            +
                          refresh_retry(what, e, schedule, *args)
         | 
| 715 | 
            +
                        else
         | 
| 716 | 
            +
                          connection = @connection
         | 
| 717 | 
            +
                          connection && connection.close(e)
         | 
| 718 | 
            +
             | 
| 719 | 
            +
                          Ione::Future.failed(e)
         | 
| 720 | 
            +
                        end
         | 
| 721 | 
            +
                      end
         | 
| 722 | 
            +
                    end
         | 
| 723 | 
            +
                  end
         | 
| 724 | 
            +
             | 
| 775 725 | 
             
                  def handle_schema_change(change)
         | 
| 776 726 | 
             
                    timer = nil
         | 
| 777 727 | 
             
                    expiration_timer = nil
         | 
| @@ -825,14 +775,17 @@ Control connection failed and is unlikely to recover. | |
| 825 775 | 
             
                  end
         | 
| 826 776 |  | 
| 827 777 | 
             
                  def send_select_request(connection, request)
         | 
| 778 | 
            +
                    backtrace = caller
         | 
| 828 779 | 
             
                    connection.send_request(request).map do |r|
         | 
| 829 780 | 
             
                      case r
         | 
| 830 781 | 
             
                      when Protocol::RowsResultResponse
         | 
| 831 782 | 
             
                        r.rows
         | 
| 832 783 | 
             
                      when Protocol::ErrorResponse
         | 
| 833 | 
            -
                         | 
| 784 | 
            +
                        e = r.to_error(nil, VOID_STATEMENT, VOID_OPTIONS, EMPTY_LIST, :one, 0)
         | 
| 785 | 
            +
                        e.set_backtrace(backtrace)
         | 
| 786 | 
            +
                        raise e
         | 
| 834 787 | 
             
                      else
         | 
| 835 | 
            -
                        raise Errors::InternalError, "Unexpected response #{r.inspect}"
         | 
| 788 | 
            +
                        raise Errors::InternalError, "Unexpected response #{r.inspect}", caller
         | 
| 836 789 | 
             
                      end
         | 
| 837 790 | 
             
                    end
         | 
| 838 791 | 
             
                  end
         |