1
votes

I am using datastax java driver 3.1.0 to connect to cassandra. I want to connect to local cassandra node always instead of connecting with remote cassandra nodes.

public class CassUtil {
  private static final Logger LOGGER = Logger.getInstance(CassUtil.class);
  private Session session;
  private Cluster cluster;

  private static class Holder {
    private static final CassUtil INSTANCE = new CassUtil();
  }

  public static CassUtil getInstance() {
    return Holder.INSTANCE;
  }

  private CassUtil() {
    List<String> servers = TestUtils.HOSTNAMES;
    String username =
        TestUtils.loadCredentialFile().getProperty(TestUtils.USERNAME);
    String password =
        TestUtils.loadCredentialFile().getProperty(TestUtils.PASSWORD);

    // this code throws exception
    PoolingOptions opts = new PoolingOptions();
    opts.setCoreConnectionsPerHost(HostDistance.LOCAL,
        opts.getCoreConnectionsPerHost(HostDistance.LOCAL));

    Builder builder = Cluster.builder();
    cluster =
        builder
            .addContactPoints(servers.toArray(new String[servers.size()]))
            .withRetryPolicy(DowngradingConsistencyRetryPolicy.INSTANCE)
            .withPoolingOptions(opts)
            .withReconnectionPolicy(new ConstantReconnectionPolicy(100L))
            .withLoadBalancingPolicy(
                DCAwareRoundRobinPolicy
                    .builder()
                    .withLocalDc(
                        !TestUtils.isProduction() ? "ABC2" : TestUtils.getCurrentLocation()
                            .get().name().toLowerCase()).build())
            .withCredentials(username, password).build();

    try {
      session = cluster.connect("testkeyspace");
    } catch (NoHostAvailableException ex) {
      LOGGER.logError("error= ", ExceptionUtils.getStackTrace(ex));
    } catch (Exception ex) {
      LOGGER.logError("error= " + ExceptionUtils.getStackTrace(ex));
    }
  }
}

Whenever I am running above code, it is throwing me an exception:

Caused by: java.lang.IllegalArgumentException: core number of connections must be positive
    at com.google.common.base.Preconditions.checkArgument(Preconditions.java:122)
    at com.datastax.driver.core.PoolingOptions.setCoreConnectionsPerHost(PoolingOptions.java:199)

Also I want to make sure that my client always connect with local cassandra nodes and not with any remote cassandra nodes.

1

1 Answers

2
votes

PoolingOptions can work with different version of protocol (V2, V3, V4) and each version has different defaults. In order to figure out which protocol is best driver must communicate with Cassandra first and then set defaults and until then driver uses -1. When you look at PoolingOptions this is even wrapped in comments above defaults (where UNSET constant is -1):

// The defaults for these fields depend on the protocol version, which is only known after control connection initialization.
// Yet if the user set them before initialization, we want to keep their values. So we use -1 to mean "uninitialized".
private final int[] coreConnections = new int[]{UNSET, UNSET, 0};

When you look at getter you are using it reads from that same array:

public int getCoreConnectionsPerHost(HostDistance distance) {
    return coreConnections[distance.ordinal()];
}

Which will effectively return -1 at the time of cluster initialization.

You can explicitly set protocol version which will fill array with right defaults (check DataStax table for versions of Cassandra/DSE and protocol versions on this link) or you can set core connection as some desired positive number instead of using getter.

Regarding question for local you can use LOCAL_ONE/LOCAL_ANY/LOCAL_QUORUM to prefer local nodes instead of remote (in different DC).