/* * 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 java.nio.ByteBuffer; import org.apache.cassandra.db.context.CounterContext; public abstract class Conflicts { private Conflicts() {} public enum Resolution { LEFT_WINS, MERGE, RIGHT_WINS }; public static Resolution resolveRegular(long leftTimestamp, boolean leftLive, int leftLocalDeletionTime, ByteBuffer leftValue, long rightTimestamp, boolean rightLive, int rightLocalDeletionTime, ByteBuffer rightValue) { if (leftTimestamp != rightTimestamp) return leftTimestamp < rightTimestamp ? Resolution.RIGHT_WINS : Resolution.LEFT_WINS; if (leftLive != rightLive) return leftLive ? Resolution.RIGHT_WINS : Resolution.LEFT_WINS; int c = leftValue.compareTo(rightValue); if (c < 0) return Resolution.RIGHT_WINS; else if (c > 0) return Resolution.LEFT_WINS; // Prefer the longest ttl if relevant return leftLocalDeletionTime < rightLocalDeletionTime ? Resolution.RIGHT_WINS : Resolution.LEFT_WINS; } public static Resolution resolveCounter(long leftTimestamp, boolean leftLive, ByteBuffer leftValue, long rightTimestamp, boolean rightLive, ByteBuffer rightValue) { // No matter what the counter cell's timestamp is, a tombstone always takes precedence. See CASSANDRA-7346. if (!leftLive) // left is a tombstone: it has precedence over right if either right is not a tombstone, or left has a greater timestamp return rightLive || leftTimestamp > rightTimestamp ? Resolution.LEFT_WINS : Resolution.RIGHT_WINS; // If right is a tombstone, since left isn't one, it has precedence if (!rightLive) return Resolution.RIGHT_WINS; // Handle empty values. Counters can't truly have empty values, but we can have a counter cell that temporarily // has one on read if the column for the cell is not queried by the user due to the optimization of #10657. We // thus need to handle this (see #11726 too). if (!leftValue.hasRemaining()) return rightValue.hasRemaining() || leftTimestamp > rightTimestamp ? Resolution.LEFT_WINS : Resolution.RIGHT_WINS; if (!rightValue.hasRemaining()) return Resolution.RIGHT_WINS; return Resolution.MERGE; } public static ByteBuffer mergeCounterValues(ByteBuffer left, ByteBuffer right) { return CounterContext.instance().merge(left, right); } }