org.apache.cassandra.db.ConsistencyLevel.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.cassandra.db.ConsistencyLevel.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.cassandra.db;

import com.carrotsearch.hppc.ObjectIntOpenHashMap;
import org.apache.cassandra.locator.Endpoints;
import org.apache.cassandra.schema.TableMetadata;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.exceptions.InvalidRequestException;
import org.apache.cassandra.locator.AbstractReplicationStrategy;
import org.apache.cassandra.locator.NetworkTopologyStrategy;
import org.apache.cassandra.transport.ProtocolException;

import static org.apache.cassandra.locator.Replicas.addToCountPerDc;
import static org.apache.cassandra.locator.Replicas.countInOurDc;

public enum ConsistencyLevel {
    ANY(0), ONE(1), TWO(2), THREE(3), QUORUM(4), ALL(5), LOCAL_QUORUM(6,
            true), EACH_QUORUM(7), SERIAL(8), LOCAL_SERIAL(9), LOCAL_ONE(10, true), NODE_LOCAL(11, true);

    // Used by the binary protocol
    public final int code;
    private final boolean isDCLocal;
    private static final ConsistencyLevel[] codeIdx;
    static {
        int maxCode = -1;
        for (ConsistencyLevel cl : ConsistencyLevel.values())
            maxCode = Math.max(maxCode, cl.code);
        codeIdx = new ConsistencyLevel[maxCode + 1];
        for (ConsistencyLevel cl : ConsistencyLevel.values()) {
            if (codeIdx[cl.code] != null)
                throw new IllegalStateException("Duplicate code");
            codeIdx[cl.code] = cl;
        }
    }

    private ConsistencyLevel(int code) {
        this(code, false);
    }

    private ConsistencyLevel(int code, boolean isDCLocal) {
        this.code = code;
        this.isDCLocal = isDCLocal;
    }

    public static ConsistencyLevel fromCode(int code) {
        if (code < 0 || code >= codeIdx.length)
            throw new ProtocolException(String.format("Unknown code %d for a consistency level", code));
        return codeIdx[code];
    }

    public static int quorumFor(Keyspace keyspace) {
        return (keyspace.getReplicationStrategy().getReplicationFactor().allReplicas / 2) + 1;
    }

    public static int localQuorumFor(Keyspace keyspace, String dc) {
        return (keyspace.getReplicationStrategy() instanceof NetworkTopologyStrategy)
                ? (((NetworkTopologyStrategy) keyspace.getReplicationStrategy())
                        .getReplicationFactor(dc).allReplicas / 2) + 1
                : quorumFor(keyspace);
    }

    public static int localQuorumForOurDc(Keyspace keyspace) {
        return localQuorumFor(keyspace, DatabaseDescriptor.getLocalDataCenter());
    }

    public static ObjectIntOpenHashMap<String> eachQuorumForRead(Keyspace keyspace) {
        NetworkTopologyStrategy strategy = (NetworkTopologyStrategy) keyspace.getReplicationStrategy();
        ObjectIntOpenHashMap<String> perDc = new ObjectIntOpenHashMap<>(strategy.getDatacenters().size());
        for (String dc : strategy.getDatacenters())
            perDc.put(dc, ConsistencyLevel.localQuorumFor(keyspace, dc));
        return perDc;
    }

    public static ObjectIntOpenHashMap<String> eachQuorumForWrite(Keyspace keyspace, Endpoints<?> pendingWithDown) {
        ObjectIntOpenHashMap<String> perDc = eachQuorumForRead(keyspace);
        addToCountPerDc(perDc, pendingWithDown, 1);
        return perDc;
    }

    public int blockFor(Keyspace keyspace) {
        switch (this) {
        case ONE:
        case LOCAL_ONE:
            return 1;
        case ANY:
            return 1;
        case TWO:
            return 2;
        case THREE:
            return 3;
        case QUORUM:
        case SERIAL:
            return quorumFor(keyspace);
        case ALL:
            return keyspace.getReplicationStrategy().getReplicationFactor().allReplicas;
        case LOCAL_QUORUM:
        case LOCAL_SERIAL:
            return localQuorumForOurDc(keyspace);
        case EACH_QUORUM:
            if (keyspace.getReplicationStrategy() instanceof NetworkTopologyStrategy) {
                NetworkTopologyStrategy strategy = (NetworkTopologyStrategy) keyspace.getReplicationStrategy();
                int n = 0;
                for (String dc : strategy.getDatacenters())
                    n += localQuorumFor(keyspace, dc);
                return n;
            } else {
                return quorumFor(keyspace);
            }
        default:
            throw new UnsupportedOperationException("Invalid consistency level: " + toString());
        }
    }

    public int blockForWrite(Keyspace keyspace, Endpoints<?> pending) {
        assert pending != null;

        int blockFor = blockFor(keyspace);
        switch (this) {
        case ANY:
            break;
        case LOCAL_ONE:
        case LOCAL_QUORUM:
        case LOCAL_SERIAL:
            // we will only count local replicas towards our response count, as these queries only care about local guarantees
            blockFor += countInOurDc(pending).allReplicas();
            break;
        case ONE:
        case TWO:
        case THREE:
        case QUORUM:
        case EACH_QUORUM:
        case SERIAL:
        case ALL:
            blockFor += pending.size();
        }
        return blockFor;
    }

    /**
     * Determine if this consistency level meets or exceeds the consistency requirements of the given cl for the given keyspace
     * WARNING: this is not locality aware; you cannot safely use this with mixed locality consistency levels (e.g. LOCAL_QUORUM and QUORUM)
     */
    public boolean satisfies(ConsistencyLevel other, Keyspace keyspace) {
        return blockFor(keyspace) >= other.blockFor(keyspace);
    }

    public boolean isDatacenterLocal() {
        return isDCLocal;
    }

    public void validateForRead(String keyspaceName) throws InvalidRequestException {
        switch (this) {
        case ANY:
            throw new InvalidRequestException("ANY ConsistencyLevel is only supported for writes");
        }
    }

    public void validateForWrite(String keyspaceName) throws InvalidRequestException {
        switch (this) {
        case SERIAL:
        case LOCAL_SERIAL:
            throw new InvalidRequestException("You must use conditional updates for serializable writes");
        }
    }

    // This is the same than validateForWrite really, but we include a slightly different error message for SERIAL/LOCAL_SERIAL
    public void validateForCasCommit(String keyspaceName) throws InvalidRequestException {
        switch (this) {
        case EACH_QUORUM:
            requireNetworkTopologyStrategy(keyspaceName);
            break;
        case SERIAL:
        case LOCAL_SERIAL:
            throw new InvalidRequestException(this
                    + " is not supported as conditional update commit consistency. Use ANY if you mean \"make sure it is accepted but I don't care how many replicas commit it for non-SERIAL reads\"");
        }
    }

    public void validateForCas() throws InvalidRequestException {
        if (!isSerialConsistency())
            throw new InvalidRequestException(
                    "Invalid consistency for conditional update. Must be one of SERIAL or LOCAL_SERIAL");
    }

    public boolean isSerialConsistency() {
        return this == SERIAL || this == LOCAL_SERIAL;
    }

    public void validateCounterForWrite(TableMetadata metadata) throws InvalidRequestException {
        if (this == ConsistencyLevel.ANY)
            throw new InvalidRequestException(
                    "Consistency level ANY is not yet supported for counter table " + metadata.name);

        if (isSerialConsistency())
            throw new InvalidRequestException("Counter operations are inherently non-serializable");
    }

    private void requireNetworkTopologyStrategy(String keyspaceName) throws InvalidRequestException {
        AbstractReplicationStrategy strategy = Keyspace.open(keyspaceName).getReplicationStrategy();
        if (!(strategy instanceof NetworkTopologyStrategy))
            throw new InvalidRequestException(
                    String.format("consistency level %s not compatible with replication strategy (%s)", this,
                            strategy.getClass().getName()));
    }
}