blob: e64cde559ac82f473e4d3e86292d041bccf8239f [file] [log] [blame]
/*
* Copyright © 2014 Cask Data, Inc.
*
* Licensed 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 co.cask.tephra;
import java.util.Arrays;
/**
* Transaction details
*/
// NOTE: this class should have minimal dependencies as it is used in HBase CPs and other places where minimal classes
// are available
public class Transaction {
private final long readPointer;
private final long writePointer;
private final long[] invalids;
private final long[] inProgress;
private final long firstShortInProgress;
private final TransactionType type;
private static final long[] NO_EXCLUDES = { };
public static final long NO_TX_IN_PROGRESS = Long.MAX_VALUE;
public static final Transaction ALL_VISIBLE_LATEST =
new Transaction(Long.MAX_VALUE, Long.MAX_VALUE, NO_EXCLUDES, NO_EXCLUDES, NO_TX_IN_PROGRESS, TransactionType.SHORT);
/**
* Creates a new transaction.
* @param readPointer read pointer for transaction
* @param writePointer write pointer for transaction
* @param invalids list of invalid transactions to exclude while reading
* @param inProgress list of in-progress transactions to exclude while reading
* @param firstShortInProgress earliest in-progress short transaction
* @param type transaction type
*/
public Transaction(long readPointer, long writePointer, long[] invalids, long[] inProgress,
long firstShortInProgress, TransactionType type) {
this.readPointer = readPointer;
this.writePointer = writePointer;
this.invalids = invalids;
this.inProgress = inProgress;
this.firstShortInProgress = firstShortInProgress;
this.type = type;
}
/**
* Creates a new short transaction.
* @param readPointer read pointer for transaction
* @param writePointer write pointer for transaction
* @param invalids list of invalid transactions to exclude while reading
* @param inProgress list of in-progress transactions to exclude while reading
* @param firstShortInProgress earliest in-progress short transaction
*/
public Transaction(long readPointer, long writePointer, long[] invalids, long[] inProgress,
long firstShortInProgress) {
this(readPointer, writePointer, invalids, inProgress, firstShortInProgress, TransactionType.SHORT);
}
public long getReadPointer() {
return readPointer;
}
public long getWritePointer() {
return writePointer;
}
public long[] getInvalids() {
return invalids;
}
public long[] getInProgress() {
return inProgress;
}
public long getFirstInProgress() {
return inProgress.length == 0 ? NO_TX_IN_PROGRESS : inProgress[0];
}
public TransactionType getType() {
return type;
}
/**
* @return transaction id {@code X} such that any of the transactions newer than {@code X} may be invisible to this<p>
* NOTE: the returned tx id can be invalid.
*/
public long getVisibilityUpperBound() {
// NOTE: in some cases when we do not provide visibility guarantee, we set readPointer to MAX value, but
// at same time we don't want that to case cleanup everything as this is used for tx janitor + ttl to see
// what can be cleaned up. When non-tx mode is implemented better, we should not need this check
return inProgress.length == 0 ? Math.min(writePointer - 1, readPointer) : inProgress[0] - 1;
}
public long getFirstShortInProgress() {
return firstShortInProgress;
}
public boolean isInProgress(long version) {
return Arrays.binarySearch(inProgress, version) >= 0;
}
public boolean isExcluded(long version) {
return Arrays.binarySearch(inProgress, version) >= 0
|| Arrays.binarySearch(invalids, version) >= 0;
}
public boolean isVisible(long version) {
// either it was committed before or the change belongs to current tx
return (version <= getReadPointer() && !isExcluded(version)) || writePointer == version;
}
public boolean hasExcludes() {
return invalids.length > 0 || inProgress.length > 0;
}
public int excludesSize() {
return invalids.length + inProgress.length;
}
@Override
public String toString() {
return new StringBuilder(100)
.append(Transaction.class.getSimpleName())
.append('{')
.append("readPointer: ").append(readPointer)
.append(", writePointer: ").append(writePointer)
.append(", invalids: ").append(Arrays.toString(invalids))
.append(", inProgress: ").append(Arrays.toString(inProgress))
.append(", firstShortInProgress: ").append(firstShortInProgress)
.append(", type: ").append(type)
.append('}')
.toString();
}
}