rocksdb/utilities/transactions/optimistic_transaction_impl.h
Manuel Ung 2005c88a75 Implement non-exclusive locks
Summary:
This is an implementation of non-exclusive locks for pessimistic transactions. It is relatively simple and does not prevent starvation (ie. it's possible that request for exclusive access will never be granted if there are always threads holding shared access). It is done by changing `KeyLockInfo` to hold an set a transaction ids, instead of just one, and adding a flag specifying whether this lock is currently held with exclusive access or not.

Some implementation notes:
- Some lock diagnostic functions had to be updated to return a set of transaction ids for a given lock, eg. `GetWaitingTxn` and `GetLockStatusData`.
- Deadlock detection is a bit more complicated since a transaction can now wait on multiple other transactions. A BFS is done in this case, and deadlock detection depth is now just a limit on the number of transactions we visit.
- Expirable transactions do not work efficiently with shared locks at the moment, but that's okay for now.
Closes https://github.com/facebook/rocksdb/pull/1573

Differential Revision: D4239097

Pulled By: lth

fbshipit-source-id: da7c074
2016-12-05 17:39:17 -08:00

99 lines
2.9 KiB
C++

// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
#pragma once
#ifndef ROCKSDB_LITE
#include <stack>
#include <string>
#include <unordered_map>
#include <vector>
#include "db/write_callback.h"
#include "rocksdb/db.h"
#include "rocksdb/slice.h"
#include "rocksdb/snapshot.h"
#include "rocksdb/status.h"
#include "rocksdb/types.h"
#include "rocksdb/utilities/transaction.h"
#include "rocksdb/utilities/optimistic_transaction_db.h"
#include "rocksdb/utilities/write_batch_with_index.h"
#include "utilities/transactions/transaction_base.h"
#include "utilities/transactions/transaction_util.h"
namespace rocksdb {
class OptimisticTransactionImpl : public TransactionBaseImpl {
public:
OptimisticTransactionImpl(OptimisticTransactionDB* db,
const WriteOptions& write_options,
const OptimisticTransactionOptions& txn_options);
virtual ~OptimisticTransactionImpl();
void Reinitialize(OptimisticTransactionDB* txn_db,
const WriteOptions& write_options,
const OptimisticTransactionOptions& txn_options);
Status Prepare() override;
Status Commit() override;
Status Rollback() override;
Status SetName(const TransactionName& name) override;
protected:
Status TryLock(ColumnFamilyHandle* column_family, const Slice& key,
bool read_only, bool exclusive,
bool untracked = false) override;
private:
OptimisticTransactionDB* const txn_db_;
friend class OptimisticTransactionCallback;
void Initialize(const OptimisticTransactionOptions& txn_options);
// Returns OK if it is safe to commit this transaction. Returns Status::Busy
// if there are read or write conflicts that would prevent us from committing
// OR if we can not determine whether there would be any such conflicts.
//
// Should only be called on writer thread.
Status CheckTransactionForConflicts(DB* db);
void Clear() override;
void UnlockGetForUpdate(ColumnFamilyHandle* column_family,
const Slice& key) override {
// Nothing to unlock.
}
// No copying allowed
OptimisticTransactionImpl(const OptimisticTransactionImpl&);
void operator=(const OptimisticTransactionImpl&);
};
// Used at commit time to trigger transaction validation
class OptimisticTransactionCallback : public WriteCallback {
public:
explicit OptimisticTransactionCallback(OptimisticTransactionImpl* txn)
: txn_(txn) {}
Status Callback(DB* db) override {
return txn_->CheckTransactionForConflicts(db);
}
bool AllowWriteBatching() override { return false; }
private:
OptimisticTransactionImpl* txn_;
};
} // namespace rocksdb
#endif // ROCKSDB_LITE