transaction_db_mutex_impl.cc 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
  2. // This source code is licensed under both the GPLv2 (found in the
  3. // COPYING file in the root directory) and Apache 2.0 License
  4. // (found in the LICENSE.Apache file in the root directory).
  5. #ifndef ROCKSDB_LITE
  6. #include "utilities/transactions/transaction_db_mutex_impl.h"
  7. #include <chrono>
  8. #include <condition_variable>
  9. #include <functional>
  10. #include <mutex>
  11. #include "rocksdb/utilities/transaction_db_mutex.h"
  12. namespace ROCKSDB_NAMESPACE {
  13. class TransactionDBMutexImpl : public TransactionDBMutex {
  14. public:
  15. TransactionDBMutexImpl() {}
  16. ~TransactionDBMutexImpl() override {}
  17. Status Lock() override;
  18. Status TryLockFor(int64_t timeout_time) override;
  19. void UnLock() override { mutex_.unlock(); }
  20. friend class TransactionDBCondVarImpl;
  21. private:
  22. std::mutex mutex_;
  23. };
  24. class TransactionDBCondVarImpl : public TransactionDBCondVar {
  25. public:
  26. TransactionDBCondVarImpl() {}
  27. ~TransactionDBCondVarImpl() override {}
  28. Status Wait(std::shared_ptr<TransactionDBMutex> mutex) override;
  29. Status WaitFor(std::shared_ptr<TransactionDBMutex> mutex,
  30. int64_t timeout_time) override;
  31. void Notify() override { cv_.notify_one(); }
  32. void NotifyAll() override { cv_.notify_all(); }
  33. private:
  34. std::condition_variable cv_;
  35. };
  36. std::shared_ptr<TransactionDBMutex>
  37. TransactionDBMutexFactoryImpl::AllocateMutex() {
  38. return std::shared_ptr<TransactionDBMutex>(new TransactionDBMutexImpl());
  39. }
  40. std::shared_ptr<TransactionDBCondVar>
  41. TransactionDBMutexFactoryImpl::AllocateCondVar() {
  42. return std::shared_ptr<TransactionDBCondVar>(new TransactionDBCondVarImpl());
  43. }
  44. Status TransactionDBMutexImpl::Lock() {
  45. mutex_.lock();
  46. return Status::OK();
  47. }
  48. Status TransactionDBMutexImpl::TryLockFor(int64_t timeout_time) {
  49. bool locked = true;
  50. if (timeout_time == 0) {
  51. locked = mutex_.try_lock();
  52. } else {
  53. // Previously, this code used a std::timed_mutex. However, this was changed
  54. // due to known bugs in gcc versions < 4.9.
  55. // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54562
  56. //
  57. // Since this mutex isn't held for long and only a single mutex is ever
  58. // held at a time, it is reasonable to ignore the lock timeout_time here
  59. // and only check it when waiting on the condition_variable.
  60. mutex_.lock();
  61. }
  62. if (!locked) {
  63. // timeout acquiring mutex
  64. return Status::TimedOut(Status::SubCode::kMutexTimeout);
  65. }
  66. return Status::OK();
  67. }
  68. Status TransactionDBCondVarImpl::Wait(
  69. std::shared_ptr<TransactionDBMutex> mutex) {
  70. auto mutex_impl = reinterpret_cast<TransactionDBMutexImpl*>(mutex.get());
  71. std::unique_lock<std::mutex> lock(mutex_impl->mutex_, std::adopt_lock);
  72. cv_.wait(lock);
  73. // Make sure unique_lock doesn't unlock mutex when it destructs
  74. lock.release();
  75. return Status::OK();
  76. }
  77. Status TransactionDBCondVarImpl::WaitFor(
  78. std::shared_ptr<TransactionDBMutex> mutex, int64_t timeout_time) {
  79. Status s;
  80. auto mutex_impl = reinterpret_cast<TransactionDBMutexImpl*>(mutex.get());
  81. std::unique_lock<std::mutex> lock(mutex_impl->mutex_, std::adopt_lock);
  82. if (timeout_time < 0) {
  83. // If timeout is negative, do not use a timeout
  84. cv_.wait(lock);
  85. } else {
  86. auto duration = std::chrono::microseconds(timeout_time);
  87. auto cv_status = cv_.wait_for(lock, duration);
  88. // Check if the wait stopped due to timing out.
  89. if (cv_status == std::cv_status::timeout) {
  90. s = Status::TimedOut(Status::SubCode::kMutexTimeout);
  91. }
  92. }
  93. // Make sure unique_lock doesn't unlock mutex when it destructs
  94. lock.release();
  95. // CV was signaled, or we spuriously woke up (but didn't time out)
  96. return s;
  97. }
  98. } // namespace ROCKSDB_NAMESPACE
  99. #endif // ROCKSDB_LITE