backend/transaction/transaction_store.h (74 lines of code) (raw):
//
// Copyright 2020 Google LLC
//
// 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.
//
#ifndef THIRD_PARTY_CLOUD_SPANNER_EMULATOR_BACKEND_TRANSACTION_TRANSACTION_STORE_H_
#define THIRD_PARTY_CLOUD_SPANNER_EMULATOR_BACKEND_TRANSACTION_TRANSACTION_STORE_H_
#include <memory>
#include "zetasql/public/value.h"
#include "absl/container/flat_hash_map.h"
#include "absl/container/flat_hash_set.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "backend/actions/ops.h"
#include "backend/common/ids.h"
#include "backend/datamodel/key.h"
#include "backend/datamodel/value.h"
#include "backend/locking/handle.h"
#include "backend/schema/catalog/column.h"
#include "backend/schema/catalog/schema.h"
#include "backend/schema/catalog/table.h"
#include "backend/storage/in_memory_iterator.h"
#include "backend/storage/storage.h"
#include "backend/transaction/commit_timestamp.h"
#include "absl/status/status.h"
namespace google {
namespace spanner {
namespace emulator {
namespace backend {
// TransactionStore buffers the mutations of a read-write transaction.
//
// Mutations applied to the TransactionStore are stored as an overlay over the
// base database storage and not actually applied to the base database storage.
//
// Multiple writes to the same row are collapsed together. For instance, an
// insert followed by a delete of the same row will clear the row from the
// TransactionStore. A delete followed by an insert followed by multiple updates
// of the same row will be collapsed into a delete and an insert for that row.
//
// Reads from the transaction store combine information from the buffered
// mutations and the base storage to provide a view of the database with the
// mutations applied. This enables read-your-write semantics provided by DML.
//
// TransactionStore is also responsible for acquiring read/write locks for
// rows and columns accessed via its interface.
//
// At commit time, the read-write transaction which owns this store flushes all
// buffered mutations to the underlying database storage in an atomic fashion.
//
// This class is not thread safe.
class TransactionStore {
public:
explicit TransactionStore(Storage* base_storage, LockHandle* lock_handle,
CommitTimestampTracker* commit_timestamp_tracker)
: base_storage_(base_storage),
lock_handle_(lock_handle),
commit_timestamp_tracker_(commit_timestamp_tracker) {}
// Buffers a write operation. Acquires write locks.
absl::Status BufferWriteOp(const WriteOp& op);
// Returns the column values for 'key' by merging information from the
// buffered mutations and the base storage. Returns NOT_FOUND if 'key'
// does not exist in the merged view. Acquires read locks.
absl::StatusOr<ValueList> Lookup(
const Table* table, const Key& key,
absl::Span<const Column* const> columns) const;
// Only reads committed values for the given key, ignoring any mutations
// buffered within the transaction. Acquires read locks.
absl::StatusOr<ValueList> ReadCommitted(
const Table* table, const Key& key,
std::vector<const Column*> columns) const;
// Returns an iterator for column values of 'key_range' by merging information
// from the buffered mutations and the base storage. Acquires read locks.
//
// Boolean flag allow_pending_commit_timestamps_in_read can be set to false to
// disallow returning pending_commit_timestamp values to clients.
absl::Status Read(const Table* table, const KeyRange& key_range,
absl::Span<const Column* const> columns,
std::unique_ptr<StorageIterator>* storage_itr,
bool allow_pending_commit_timestamps_in_read = true) const;
// Returns the buffered mutations.
std::vector<WriteOp> GetBufferedOps() const;
// Clears the buffered mutations.
void Clear() { buffered_ops_.clear(); }
private:
// Types of mutations.
enum class OpType {
kInsert,
kUpdate,
kDelete,
};
using RowOp = std::pair<OpType, Row>;
// Acquires read locks for the specified column ranges.
absl::Status AcquireReadLock(const Table* table, const KeyRange& key_range,
absl::Span<const Column* const> columns) const;
// Acquires write locks for the specified column ranges.
absl::Status AcquireWriteLock(const Table* table, const KeyRange& key_range,
absl::Span<const Column* const> columns) const;
// Buffers an insert mutation. Acquires write locks.
absl::Status BufferInsert(const Table* table, const Key& key,
absl::Span<const Column* const> columns,
const ValueList& values);
// Buffers an update mutation. Acquires write locks.
absl::Status BufferUpdate(const Table* table, const Key& key,
absl::Span<const Column* const> columns,
const ValueList& values);
// Buffers a delete mutation. Acquires write locks.
absl::Status BufferDelete(const Table* table, const Key& key);
// Returns true if a row already exists in base_storage_.
bool RowExistsInStorage(const Table* table, const Key& key);
// Returns true if a mutation has been buffered for 'key' and fills 'row'.
bool RowExistsInBuffer(const Table* table, const Key& key, RowOp* row) const;
// Underlying storage for the database.
const Storage* base_storage_;
// Handle for the lock manager.
LockHandle* lock_handle_;
// Map that stores the buffered mutations.
absl::flat_hash_map<const Table*, std::map<Key, RowOp>> buffered_ops_;
// Tracks tables/columns containing pending commit timestamps.
const CommitTimestampTracker* commit_timestamp_tracker_;
};
} // namespace backend
} // namespace emulator
} // namespace spanner
} // namespace google
#endif // THIRD_PARTY_CLOUD_SPANNER_EMULATOR_BACKEND_TRANSACTION_TRANSACTION_STORE_H_