Uploaded image for project: 'Cassandra'
  1. Cassandra
  2. CASSANDRA-19468

In some situations MetadataManager.SingleThreaded.startSchemaRequest could fail to set CompletableFuture arg

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Resolved
    • Normal
    • Resolution: Fixed
    • None
    • Client/java-driver
    • None
    • All
    • None

    Description

      Relevant code is:

       

       

      private void startSchemaRequest(CompletableFuture<RefreshSchemaResult> refreshFuture) {
        assert adminExecutor.inEventLoop();
        if (closeWasCalled) {
          refreshFuture.complete(new RefreshSchemaResult(metadata));
          return;
        }
        if (currentSchemaRefresh == null) {
          currentSchemaRefresh = refreshFuture;
          LOG.debug("[{}] Starting schema refresh", logPrefix);
          initControlConnectionForSchema()
              .thenCompose(v -> context.getTopologyMonitor().checkSchemaAgreement())
              .whenComplete(
                  (schemaInAgreement, agreementError) -> {
                    if (agreementError != null) {
                      refreshFuture.completeExceptionally(agreementError);
                    } else {
                      schemaQueriesFactory
                          .newInstance()
                          .execute()
                          .thenApplyAsync(this::parseAndApplySchemaRows, adminExecutor)
                          .whenComplete(
                              (newMetadata, metadataError) -> {
                                if (metadataError != null) {
                                  refreshFuture.completeExceptionally(metadataError);
                                } else {
                                  refreshFuture.complete(
                                      new RefreshSchemaResult(newMetadata, schemaInAgreement));
                                }
      
      ...

       

       

      Problem is that the default impl of SchemaQueriesFactory (DefaultSchemaQueriesFactory) can chuck exceptions in a few cases, most notably if the control connection is in a bad way:

       

       

      @Override
      public SchemaQueries newInstance() {
        DriverChannel channel = context.getControlConnection().channel();
        if (channel == null || channel.closeFuture().isDone()) {
          throw new IllegalStateException("Control channel not available, aborting schema refresh");
        }
        Node node =
            context
                .getMetadataManager()
                .getMetadata()
                .findNode(channel.getEndPoint())
                .orElseThrow(
                    () ->
                        new IllegalStateException(
                            "Could not find control node metadata "
                                + channel.getEndPoint()
                                + ", aborting schema refresh"));
        return newInstance(node, channel);
      } 

       

       

       

      In this case the MetadataManager code above will exit out before it ever sets a state on refreshFuture... meaning anything waiting on that future will just continue to wait.

       

       

      Attachments

        Issue Links

          Activity

            People

              akhaku Ammar Khaku
              absurdfarce Bret McGuire
              Ammar Khaku
              Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved:

                Time Tracking

                  Estimated:
                  Original Estimate - Not Specified
                  Not Specified
                  Remaining:
                  Remaining Estimate - 0h
                  0h
                  Logged:
                  Time Spent - 40m
                  40m