blob: fe254096e44a47dc978a17670e60fd8bd03ee72c [file] [log] [blame]
// 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.
#pragma once
#include <atomic>
#include <cstdint>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#include "kudu/gutil/ref_counted.h"
#include "kudu/transactions/transactions.pb.h"
#include "kudu/util/cow_object.h"
#include "kudu/util/locks.h"
#include "kudu/util/monotime.h"
namespace kudu {
namespace transactions {
typedef std::pair<std::string, TxnParticipantEntryPB> ParticipantIdAndPB;
// Representations of entries in the transaction status table. Currently there
// are two entry types:
// - Transaction Entries: these indicate the existence of a transaction, and
// encapsulate encapsulate metadata that pertain to the entire transactions
// (e.g. owner, commit status, commit timestamp).
// - Participant Entries: these indicate the existence of a tablet that is
// participating in a transaction.
//
// There is a 1:N relationship between transaction entries and participant
// entries. Represents the metadata persisted with a participant entry in the
// transaction status table.
struct PersistentParticipantEntry {
TxnParticipantEntryPB pb;
};
class ParticipantEntry : public RefCountedThreadSafe<ParticipantEntry> {
public:
typedef PersistentParticipantEntry cow_state;
ParticipantEntry() = default;
const CowObject<PersistentParticipantEntry>& metadata() const { return metadata_; }
CowObject<PersistentParticipantEntry>* mutable_metadata() { return &metadata_; }
private:
friend class RefCountedThreadSafe<ParticipantEntry>;
~ParticipantEntry() = default;
// Mutable state for this participant with concurrent access controlled via
// copy-on-write locking.
CowObject<PersistentParticipantEntry> metadata_;
};
// Represents the metadata persisted with a status entry in the transaction
// status table.
struct PersistentTransactionEntry {
TxnStatusEntryPB pb;
};
class TransactionEntry : public RefCountedThreadSafe<TransactionEntry> {
public:
typedef PersistentTransactionEntry cow_state;
TransactionEntry(int64_t txn_id, std::string user);
const CowObject<PersistentTransactionEntry>& metadata() const { return metadata_; }
CowObject<PersistentTransactionEntry>* mutable_metadata() { return &metadata_; }
// Adds a participant with the given tablet ID, or returns the one if it
// already exists.
scoped_refptr<ParticipantEntry> GetOrCreateParticipant(const std::string& tablet_id);
// Returns the list of tablet IDs associated with this transaction.
std::vector<std::string> GetParticipantIds() const;
const std::string& user() const {
return user_;
}
// Return the last recorded heartbeat timestamp for the transaction.
MonoTime last_heartbeat_time() const {
return last_heartbeat_time_.load();
}
// Set the timestamp of last seen keep-alive heartbeat for the transaction.
void SetLastHeartbeatTime(const MonoTime& hbtime) {
last_heartbeat_time_.store(hbtime);
}
// An accessor to the transaction's state. Concurrent access is controlled
// via the locking provided by the underlying copy-on-write metadata_ object.
TxnStatePB state() const;
private:
friend class RefCountedThreadSafe<TransactionEntry>;
~TransactionEntry() = default;
const int64_t txn_id_;
// While this is redundant with the field in the protobuf, it's convenient to
// cache this so we don't have to lock this entry to get the user.
const std::string user_;
// Protects participants_. If adding a new participant, the entry should also
// be locked in read mode and the transaction should be open.
mutable simple_spinlock lock_;
std::unordered_map<std::string, scoped_refptr<ParticipantEntry>> participants_;
// Mutable state for the transaction status record with concurrent access
// controlled via copy-on-write locking.
CowObject<PersistentTransactionEntry> metadata_;
// Time of the last keep-alive heartbeat received for the transaction
// identified by txn_id_. Using std::atomic wrapper since the field can be
// accessed concurrently by multiple threads:
// * the field can be updated by concurrent KeepAlive requests from
// different clients sending writes in the context of the same transaction
// * the field is read by the stale transaction tracker in TxnStatusManager
std::atomic<MonoTime> last_heartbeat_time_;
};
typedef MetadataLock<TransactionEntry> TransactionEntryLock;
typedef MetadataLock<ParticipantEntry> ParticipantEntryLock;
} // namespace transactions
} // namespace kudu