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

com.palantir.atlasdb.lock.SimpleEteLockWatchResource Maven / Gradle / Ivy

/*
 * (c) Copyright 2020 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.lock;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.palantir.atlasdb.AtlasDbConstants;
import com.palantir.atlasdb.encoding.PtBytes;
import com.palantir.atlasdb.keyvalue.api.Cell;
import com.palantir.atlasdb.keyvalue.api.KeyValueService;
import com.palantir.atlasdb.keyvalue.api.Namespace;
import com.palantir.atlasdb.keyvalue.api.TableReference;
import com.palantir.atlasdb.keyvalue.api.watch.ExposedLockWatchManager;
import com.palantir.atlasdb.transaction.api.OpenTransaction;
import com.palantir.atlasdb.transaction.api.PreCommitCondition;
import com.palantir.atlasdb.transaction.api.Transaction;
import com.palantir.atlasdb.transaction.api.TransactionManager;
import com.palantir.common.streams.KeyedStream;
import com.palantir.lock.watch.CommitUpdate;
import com.palantir.lock.watch.LockWatchReferences;
import com.palantir.lock.watch.TransactionsLockWatchUpdate;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicReference;
import org.immutables.value.Value;

public final class SimpleEteLockWatchResource implements EteLockWatchResource {
    public static final Namespace NAMESPACE = Namespace.create("lock");
    private static final byte[] VALUE = PtBytes.toBytes("value");
    private static final byte[] COLUMN = PtBytes.toBytes("b");

    private final TransactionManager transactionManager;
    private final ExposedLockWatchManager lockWatchManager;
    private final Map activeTransactions = new ConcurrentHashMap<>();

    private String table = "watch";
    private TableReference lockWatchTable = TableReference.create(NAMESPACE, table);

    public SimpleEteLockWatchResource(TransactionManager transactionManager) {
        this.transactionManager = transactionManager;
        createTable();
        this.lockWatchManager = new ExposedLockWatchManager(transactionManager.getLockWatchManager());
    }

    @Override
    public TransactionId startTransaction() {
        CommitUpdateCondition condition = new CommitUpdateCondition();
        OpenTransaction transaction =
                Iterables.getOnlyElement(transactionManager.startTransactions(ImmutableList.of(condition)));
        TransactionId id = TransactionId.of(transaction.getTimestamp());
        condition.setStartTs(transaction.getTimestamp());
        activeTransactions.put(id, TransactionAndCondition.of(transaction, condition));
        return id;
    }

    @Override
    public Optional endTransaction(TransactionId transactionId) {
        TransactionAndCondition txnAndCondition = activeTransactions.remove(transactionId);
        txnAndCondition.transaction().commit();
        txnAndCondition.transaction().finish(unused -> null);
        txnAndCondition.condition().cleanup();
        return Optional.ofNullable(txnAndCondition.condition().getCommitUpdate());
    }

    @Override
    public void write(WriteRequest writeRequest) {
        Transaction transaction = activeTransactions.get(writeRequest.id()).transaction();
        Map byteValues = getValueMap(writeRequest.rows());
        transaction.put(lockWatchTable, byteValues);
    }

    @Override
    public TransactionsLockWatchUpdate getUpdate(GetLockWatchUpdateRequest updateRequest) {
        return lockWatchManager.getUpdateForTransactions(updateRequest.startTimestamps(), updateRequest.version());
    }

    @Override
    public void setTable(String tableName) {
        table = tableName;
        lockWatchTable = TableReference.create(NAMESPACE, table);
        createTable();
    }

    private void createTable() {
        KeyValueService keyValueService = transactionManager.getKeyValueService();
        keyValueService.createTable(lockWatchTable, AtlasDbConstants.GENERIC_TABLE_METADATA);
        transactionManager
                .getLockWatchManager()
                .registerPreciselyWatches(
                        ImmutableSet.of(LockWatchReferences.entireTable(lockWatchTable.getQualifiedName())));
    }

    private Map getValueMap(Set rows) {
        return KeyedStream.of(rows)
                .mapKeys(PtBytes::toBytes)
                .mapKeys(row -> Cell.create(row, COLUMN))
                .map(unused -> VALUE)
                .collectToMap();
    }

    @Value.Immutable
    interface TransactionAndCondition {
        @Value.Parameter
        OpenTransaction transaction();

        @Value.Parameter
        CommitUpdateCondition condition();

        static TransactionAndCondition of(OpenTransaction transaction, CommitUpdateCondition condition) {
            return ImmutableTransactionAndCondition.of(transaction, condition);
        }
    }

    class CommitUpdateCondition implements PreCommitCondition {
        private final AtomicReference commitUpdate = new AtomicReference<>();
        private Optional startTs = Optional.empty();

        CommitUpdateCondition() {}

        void setStartTs(long startTs) {
            this.startTs = Optional.of(startTs);
        }

        CommitUpdate getCommitUpdate() {
            return commitUpdate.get();
        }

        @Override
        public void throwIfConditionInvalid(long timestamp) {
            startTs.filter(ts -> ts != timestamp)
                    .ifPresent(ts -> commitUpdate.set(lockWatchManager.getCommitUpdate(ts)));
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy