| /* |
| * 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); |
| } |
| |
| } |