All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.palantir.atlasdb.cassandra.backup.transaction.Transactions1TableInteraction Maven / Gradle / Ivy

The newest version!
/*
 * (c) Copyright 2021 Palantir Technologies Inc. All rights reserved.
 *
 * 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 com.palantir.atlasdb.cassandra.backup.transaction;

import com.datastax.driver.core.BoundStatement;
import com.datastax.driver.core.ConsistencyLevel;
import com.datastax.driver.core.PreparedStatement;
import com.datastax.driver.core.Row;
import com.datastax.driver.core.Statement;
import com.datastax.driver.core.TableMetadata;
import com.datastax.driver.core.policies.DefaultRetryPolicy;
import com.datastax.driver.core.policies.RetryPolicy;
import com.datastax.driver.core.querybuilder.QueryBuilder;
import com.datastax.driver.core.utils.Bytes;
import com.google.common.collect.ImmutableList;
import com.palantir.atlasdb.cassandra.backup.CqlSession;
import com.palantir.atlasdb.keyvalue.api.Cell;
import com.palantir.atlasdb.keyvalue.cassandra.CassandraConstants;
import com.palantir.atlasdb.transaction.encoding.V1EncodingStrategy;
import com.palantir.atlasdb.transaction.impl.TransactionConstants;
import com.palantir.atlasdb.transaction.impl.TransactionStatusUtils;
import com.palantir.atlasdb.transaction.service.TransactionStatus;
import com.palantir.timestamp.FullyBoundedTimestampRange;
import java.nio.ByteBuffer;
import java.util.List;

public class Transactions1TableInteraction implements TransactionsTableInteraction {
    private final FullyBoundedTimestampRange timestampRange;
    private final RetryPolicy abortRetryPolicy;

    public Transactions1TableInteraction(FullyBoundedTimestampRange timestampRange, RetryPolicy abortRetryPolicy) {
        this.timestampRange = timestampRange;
        this.abortRetryPolicy = abortRetryPolicy;
    }

    private static final byte[] DUMMY = new byte[] {1};
    private static final byte[] ABORT_COMMIT_TS_ENCODED =
            V1EncodingStrategy.INSTANCE.encodeCommitStatusAsValue(0, TransactionStatus.aborted());
    static final ByteBuffer COLUMN_NAME_BB = ByteBuffer.wrap(TransactionConstants.COMMIT_TS_COLUMN);

    @Override
    public FullyBoundedTimestampRange getTimestampRange() {
        return timestampRange;
    }

    @Override
    public String getTransactionsTableName() {
        return TransactionConstants.TRANSACTION_TABLE.getTableName();
    }

    @Override
    public PreparedStatement prepareAbortStatement(TableMetadata transactionsTable, CqlSession session) {
        Statement abortStatement = QueryBuilder.update(transactionsTable)
                .with(QueryBuilder.set(CassandraConstants.VALUE, ByteBuffer.wrap(ABORT_COMMIT_TS_ENCODED)))
                .where(QueryBuilder.eq(CassandraConstants.ROW, QueryBuilder.bindMarker()))
                .and(QueryBuilder.eq(CassandraConstants.COLUMN, COLUMN_NAME_BB))
                .and(QueryBuilder.eq(CassandraConstants.TIMESTAMP, CassandraConstants.ENCODED_CAS_TABLE_TIMESTAMP))
                .onlyIf(QueryBuilder.eq(CassandraConstants.VALUE, QueryBuilder.bindMarker()));
        // if you change this from CAS then you must update RetryPolicy
        return session.prepare(abortStatement);
    }

    @Override
    public PreparedStatement prepareCheckStatement(TableMetadata transactionsTable, CqlSession session) {
        Statement checkStatement = QueryBuilder.select()
                .from(transactionsTable)
                .where(QueryBuilder.eq(CassandraConstants.ROW, QueryBuilder.bindMarker()))
                .and(QueryBuilder.eq(CassandraConstants.COLUMN, COLUMN_NAME_BB))
                .and(QueryBuilder.eq(CassandraConstants.TIMESTAMP, CassandraConstants.ENCODED_CAS_TABLE_TIMESTAMP));
        return session.prepare(checkStatement);
    }

    @Override
    public TransactionTableEntry extractTimestamps(Row row) {
        long startTimestamp = decodeStartTs(Bytes.getArray(row.getBytes(CassandraConstants.ROW)));
        TransactionStatus commitStatus = decodeCommitTs(Bytes.getArray(row.getBytes(CassandraConstants.VALUE)));
        return TransactionTableEntryUtils.fromStatus(startTimestamp, commitStatus);
    }

    @Override
    public Statement bindCheckStatement(PreparedStatement preparedCheckStatement, TransactionTableEntry entry) {
        long startTs = TransactionTableEntries.getStartTimestamp(entry);
        ByteBuffer startTimestampBb = encodeStartTimestamp(startTs);
        BoundStatement bound = preparedCheckStatement.bind(startTimestampBb);
        return bound.setConsistencyLevel(ConsistencyLevel.QUORUM)
                .setSerialConsistencyLevel(ConsistencyLevel.SERIAL)
                .setReadTimeoutMillis(LONG_READ_TIMEOUT_MS)
                .setRetryPolicy(DefaultRetryPolicy.INSTANCE);
    }

    @Override
    public Statement bindAbortStatement(PreparedStatement preparedAbortStatement, TransactionTableEntry entry) {
        long startTs = TransactionTableEntries.getStartTimestamp(entry);
        long commitTs = TransactionTableEntries.getCommitTimestamp(entry).orElseThrow(() -> illegalEntry(entry));
        ByteBuffer startTimestampBb = encodeStartTimestamp(startTs);
        ByteBuffer commitTimestampBb = encodeCommitTimestamp(commitTs);
        BoundStatement bound = preparedAbortStatement.bind(startTimestampBb, commitTimestampBb);
        return bound.setConsistencyLevel(ConsistencyLevel.QUORUM)
                .setSerialConsistencyLevel(ConsistencyLevel.SERIAL)
                .setDefaultTimestamp(CassandraConstants.CAS_TABLE_TIMESTAMP)
                .setReadTimeoutMillis(LONG_READ_TIMEOUT_MS)
                .setIdempotent(true) // by default CAS operations are not idempotent in case of multiple clients
                .setRetryPolicy(abortRetryPolicy);
    }

    @Override
    public List createSelectStatementsForScanningFullTimestampRange(TableMetadata transactionsTable) {
        Statement select = QueryBuilder.select()
                .all()
                .from(transactionsTable)
                .where(QueryBuilder.lte(
                        QueryBuilder.token(CassandraConstants.ROW),
                        QueryBuilder.token(encodeStartTimestamp(timestampRange.inclusiveUpperBound()))))
                .and(QueryBuilder.gte(
                        QueryBuilder.token(CassandraConstants.ROW),
                        QueryBuilder.token(encodeStartTimestamp(timestampRange.inclusiveLowerBound()))))
                .setConsistencyLevel(ConsistencyLevel.QUORUM)
                .setFetchSize(SELECT_TRANSACTIONS_FETCH_SIZE)
                .setReadTimeoutMillis(LONG_READ_TIMEOUT_MS);

        return ImmutableList.of(select);
    }

    static ByteBuffer encodeStartTimestamp(long timestamp) {
        return ByteBuffer.wrap(V1EncodingStrategy.INSTANCE
                .encodeStartTimestampAsCell(timestamp)
                .getRowName());
    }

    private long decodeStartTs(byte[] startTsRow) {
        return V1EncodingStrategy.INSTANCE.decodeCellAsStartTimestamp(Cell.create(startTsRow, DUMMY));
    }

    static ByteBuffer encodeCommitTimestamp(long timestamp) {
        return ByteBuffer.wrap(V1EncodingStrategy.INSTANCE.encodeCommitStatusAsValue(
                0, TransactionStatusUtils.fromTimestamp(timestamp)));
    }

    private TransactionStatus decodeCommitTs(byte[] value) {
        return V1EncodingStrategy.INSTANCE.decodeValueAsCommitStatus(0, value);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy