This is an automated email from the ASF dual-hosted git repository.

twice pushed a commit to branch unstable
in repository https://gitbox.apache.org/repos/asf/kvrocks.git


The following commit(s) were added to refs/heads/unstable by this push:
     new 04c5a922 Make lock guard movable & accept generalized arguments (#1636)
04c5a922 is described below

commit 04c5a922a71850d2e143297c30baf87d99e9e075
Author: Twice <[email protected]>
AuthorDate: Sun Aug 6 07:11:40 2023 +0800

    Make lock guard movable & accept generalized arguments (#1636)
---
 .clang-tidy                 |   2 +-
 src/common/lock_manager.h   | 130 ++++++++++++++++++++++++++++++++++++++++++++
 src/storage/lock_manager.cc |  62 ---------------------
 src/storage/lock_manager.h  |  88 ------------------------------
 src/types/redis_set.cc      |   5 +-
 src/types/redis_zset.cc     |  13 +++--
 6 files changed, 141 insertions(+), 159 deletions(-)

diff --git a/.clang-tidy b/.clang-tidy
index ccc27aec..09e05a96 100644
--- a/.clang-tidy
+++ b/.clang-tidy
@@ -1,5 +1,5 @@
 # refer to https://clang.llvm.org/extra/clang-tidy/checks/list.html
-Checks: -*, clang-analyzer-core.*, clang-analyzer-cplusplus.*, 
clang-analyzer-deadcode.*, clang-analyzer-nullability.*, 
clang-analyzer-security.*, clang-analyzer-unix.*, clang-analyzer-valist.*, 
cppcoreguidelines-init-variables, cppcoreguidelines-macro-usage, 
cppcoreguidelines-interfaces-global-init, 
cppcoreguidelines-narrowing-conversions, cppcoreguidelines-no-malloc, 
cppcoreguidelines-prefer-member-initializer, 
cppcoreguidelines-special-member-functions, cppcoreguidelines-slicing, goog 
[...]
+Checks: -*, clang-analyzer-core.*, clang-analyzer-cplusplus.*, 
-clang-analyzer-cplusplus.InnerPointer, clang-analyzer-deadcode.*, 
clang-analyzer-nullability.*, clang-analyzer-security.*, clang-analyzer-unix.*, 
clang-analyzer-valist.*, cppcoreguidelines-init-variables, 
cppcoreguidelines-macro-usage, cppcoreguidelines-interfaces-global-init, 
cppcoreguidelines-narrowing-conversions, cppcoreguidelines-no-malloc, 
cppcoreguidelines-prefer-member-initializer, 
cppcoreguidelines-special-member-fu [...]
 
 WarningsAsErrors: clang-analyzer-*, -clang-analyzer-security.insecureAPI.rand, 
google-*, performance-*, cppcoreguidelines-*, modernize-*, readability-*, 
bugprone-*
 
diff --git a/src/common/lock_manager.h b/src/common/lock_manager.h
new file mode 100644
index 00000000..9e4d98ad
--- /dev/null
+++ b/src/common/lock_manager.h
@@ -0,0 +1,130 @@
+/*
+ * 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 <rocksdb/db.h>
+
+#include <functional>
+#include <mutex>
+#include <set>
+#include <string>
+#include <vector>
+
+class LockManager {
+ public:
+  explicit LockManager(unsigned hash_power) : hash_power_(hash_power), 
hash_mask_((1U << hash_power) - 1) {
+    mutex_pool_.reserve(Size());
+    for (unsigned i = 0; i < Size(); i++) {
+      mutex_pool_.emplace_back(new std::mutex{});
+    }
+  }
+  ~LockManager() = default;
+
+  LockManager(const LockManager &) = delete;
+  LockManager &operator=(const LockManager &) = delete;
+
+  unsigned Size() const { return (1U << hash_power_); }
+
+  void Lock(std::string_view key) { mutex_pool_[hash(key)]->lock(); }
+  void UnLock(std::string_view key) { mutex_pool_[hash(key)]->unlock(); }
+  void Lock(rocksdb::Slice key) { Lock(key.ToStringView()); }
+  void UnLock(rocksdb::Slice key) { UnLock(key.ToStringView()); }
+
+  template <typename Keys>
+  std::vector<std::mutex *> MultiGet(const Keys &keys) {
+    std::set<unsigned, std::greater<unsigned>> to_acquire_indexes;
+    // We are using the `set` to avoid retrieving the mutex, as well as 
guarantee to retrieve
+    // the order of locks.
+    //
+    // For example, we need lock the key `A` and `B` and they have the same 
lock hash
+    // index, it will be deadlock if lock the same mutex twice. Besides, we 
also need
+    // to order the mutex before acquiring locks since different threads may 
acquire
+    // same keys with different order.
+    for (const auto &key : keys) {
+      to_acquire_indexes.insert(hash(key));
+    }
+
+    std::vector<std::mutex *> locks;
+    locks.reserve(to_acquire_indexes.size());
+    for (auto index : to_acquire_indexes) {
+      locks.emplace_back(mutex_pool_[index].get());
+    }
+    return locks;
+  }
+
+ private:
+  unsigned hash_power_;
+  unsigned hash_mask_;
+  std::vector<std::unique_ptr<std::mutex>> mutex_pool_;
+
+  unsigned hash(std::string_view key) const { return 
std::hash<std::string_view>{}(key)&hash_mask_; }
+};
+
+template <typename KeyType>
+class BasicLockGuard {
+ public:
+  explicit BasicLockGuard(LockManager *lock_mgr, KeyType key) : 
lock_mgr_(lock_mgr), key_(std::move(key)) {
+    lock_mgr->Lock(key_);
+  }
+  ~BasicLockGuard() {
+    if (lock_mgr_) lock_mgr_->UnLock(key_);
+  }
+
+  BasicLockGuard(const BasicLockGuard &) = delete;
+  BasicLockGuard &operator=(const BasicLockGuard &) = delete;
+
+  BasicLockGuard(BasicLockGuard &&guard) : lock_mgr_(guard.lock_mgr_), 
key_(std::move(guard.key_)) {
+    guard.lock_mgr_ = nullptr;
+  }
+
+ private:
+  LockManager *lock_mgr_ = nullptr;
+  KeyType key_;
+};
+
+using LockGuard = BasicLockGuard<rocksdb::Slice>;
+
+class MultiLockGuard {
+ public:
+  template <typename Keys>
+  explicit MultiLockGuard(LockManager *lock_mgr, const Keys &keys)
+      : lock_mgr_(lock_mgr), locks_(lock_mgr_->MultiGet(keys)) {
+    for (const auto &iter : locks_) {
+      iter->lock();
+    }
+  }
+
+  ~MultiLockGuard() {
+    // Lock with order `A B C` and unlock should be `C B A`
+    for (auto iter = locks_.rbegin(); iter != locks_.rend(); ++iter) {
+      (*iter)->unlock();
+    }
+  }
+
+  MultiLockGuard(const MultiLockGuard &) = delete;
+  MultiLockGuard &operator=(const MultiLockGuard &) = delete;
+
+  MultiLockGuard(MultiLockGuard &&guard) : lock_mgr_(guard.lock_mgr_), 
locks_(std::move(guard.locks_)) {}
+
+ private:
+  LockManager *lock_mgr_ = nullptr;
+  std::vector<std::mutex *> locks_;
+};
diff --git a/src/storage/lock_manager.cc b/src/storage/lock_manager.cc
deleted file mode 100644
index 6a1d550d..00000000
--- a/src/storage/lock_manager.cc
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * 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.
- *
- */
-
-#include "lock_manager.h"
-
-#include <set>
-#include <string>
-#include <thread>
-
-LockManager::LockManager(int hash_power) : hash_power_(hash_power), 
hash_mask_((1U << hash_power) - 1) {
-  for (unsigned i = 0; i < Size(); i++) {
-    mutex_pool_.emplace_back(new std::mutex{});
-  }
-}
-
-unsigned LockManager::hash(const rocksdb::Slice &key) const {
-  return std::hash<std::string_view>{}(std::string_view{key.data(), 
key.size()}) & hash_mask_;
-}
-
-unsigned LockManager::Size() const { return (1U << hash_power_); }
-
-void LockManager::Lock(const rocksdb::Slice &key) { 
mutex_pool_[hash(key)]->lock(); }
-
-void LockManager::UnLock(const rocksdb::Slice &key) { 
mutex_pool_[hash(key)]->unlock(); }
-
-std::vector<std::mutex *> LockManager::MultiGet(const std::vector<std::string> 
&keys) {
-  std::set<unsigned, std::greater<unsigned>> to_acquire_indexes;
-  // We are using the `set` to avoid retrieving the mutex, as well as 
guarantee to retrieve
-  // the order of locks.
-  //
-  // For example, we need lock the key `A` and `B` and they have the same lock 
hash
-  // index, it will be deadlock if lock the same mutex twice. Besides, we also 
need
-  // to order the mutex before acquiring locks since different threads may 
acquire
-  // same keys with different order.
-  for (const auto &key : keys) {
-    to_acquire_indexes.insert(hash(key));
-  }
-
-  std::vector<std::mutex *> locks;
-  locks.reserve(to_acquire_indexes.size());
-  for (auto index : to_acquire_indexes) {
-    locks.emplace_back(mutex_pool_[index].get());
-  }
-  return locks;
-}
diff --git a/src/storage/lock_manager.h b/src/storage/lock_manager.h
deleted file mode 100644
index 43a28eb5..00000000
--- a/src/storage/lock_manager.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * 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 <rocksdb/db.h>
-
-#include <functional>
-#include <mutex>
-#include <string>
-#include <vector>
-
-class LockManager {
- public:
-  explicit LockManager(int hash_power);
-  ~LockManager() = default;
-
-  LockManager(const LockManager &) = delete;
-  LockManager &operator=(const LockManager &) = delete;
-
-  unsigned Size() const;
-  void Lock(const rocksdb::Slice &key);
-  void UnLock(const rocksdb::Slice &key);
-  std::vector<std::mutex *> MultiGet(const std::vector<std::string> &keys);
-
- private:
-  int hash_power_;
-  unsigned hash_mask_;
-  std::vector<std::unique_ptr<std::mutex>> mutex_pool_;
-
-  unsigned hash(const rocksdb::Slice &key) const;
-};
-
-class LockGuard {
- public:
-  explicit LockGuard(LockManager *lock_mgr, rocksdb::Slice key) : 
lock_mgr_(lock_mgr), key_(key) {
-    lock_mgr->Lock(key_);
-  }
-  ~LockGuard() { lock_mgr_->UnLock(key_); }
-
-  LockGuard(const LockGuard &) = delete;
-  LockGuard &operator=(const LockGuard &) = delete;
-
- private:
-  LockManager *lock_mgr_ = nullptr;
-  rocksdb::Slice key_;
-};
-
-class MultiLockGuard {
- public:
-  explicit MultiLockGuard(LockManager *lock_mgr, const 
std::vector<std::string> &keys) : lock_mgr_(lock_mgr) {
-    locks_ = lock_mgr_->MultiGet(keys);
-    for (const auto &iter : locks_) {
-      iter->lock();
-    }
-  }
-
-  ~MultiLockGuard() {
-    // Lock with order `A B C` and unlock should be `C B A`
-    for (auto iter = locks_.rbegin(); iter != locks_.rend(); ++iter) {
-      (*iter)->unlock();
-    }
-  }
-
-  MultiLockGuard(const MultiLockGuard &) = delete;
-  MultiLockGuard &operator=(const MultiLockGuard &) = delete;
-
- private:
-  LockManager *lock_mgr_ = nullptr;
-  std::vector<std::mutex *> locks_;
-};
diff --git a/src/types/redis_set.cc b/src/types/redis_set.cc
index 588b0e3a..31970ff1 100644
--- a/src/types/redis_set.cc
+++ b/src/types/redis_set.cc
@@ -22,6 +22,7 @@
 
 #include <map>
 #include <memory>
+#include <optional>
 
 #include "db_util.h"
 
@@ -203,8 +204,8 @@ rocksdb::Status Set::Take(const Slice &user_key, 
std::vector<std::string> *membe
   std::string ns_key;
   AppendNamespacePrefix(user_key, &ns_key);
 
-  std::unique_ptr<LockGuard> lock_guard;
-  if (pop) lock_guard = 
std::make_unique<LockGuard>(storage_->GetLockManager(), ns_key);
+  std::optional<LockGuard> lock_guard;
+  if (pop) lock_guard.emplace(storage_->GetLockManager(), ns_key);
 
   SetMetadata metadata(false);
   rocksdb::Status s = GetMetadata(ns_key, &metadata);
diff --git a/src/types/redis_zset.cc b/src/types/redis_zset.cc
index e7a1585d..d0994b06 100644
--- a/src/types/redis_zset.cc
+++ b/src/types/redis_zset.cc
@@ -24,6 +24,7 @@
 #include <limits>
 #include <map>
 #include <memory>
+#include <optional>
 #include <set>
 
 #include "db_util.h"
@@ -229,8 +230,8 @@ rocksdb::Status ZSet::RangeByRank(const Slice &user_key, 
const RangeRankSpec &sp
   std::string ns_key;
   AppendNamespacePrefix(user_key, &ns_key);
 
-  std::unique_ptr<LockGuard> lock_guard;
-  if (spec.with_deletion) lock_guard = 
std::make_unique<LockGuard>(storage_->GetLockManager(), ns_key);
+  std::optional<LockGuard> lock_guard;
+  if (spec.with_deletion) lock_guard.emplace(storage_->GetLockManager(), 
ns_key);
   ZSetMetadata metadata(false);
   rocksdb::Status s = GetMetadata(ns_key, &metadata);
   if (!s.ok()) return s.IsNotFound() ? rocksdb::Status::OK() : s;
@@ -311,8 +312,8 @@ rocksdb::Status ZSet::RangeByScore(const Slice &user_key, 
const RangeScoreSpec &
   std::string ns_key;
   AppendNamespacePrefix(user_key, &ns_key);
 
-  std::unique_ptr<LockGuard> lock_guard;
-  if (spec.with_deletion) lock_guard = 
std::make_unique<LockGuard>(storage_->GetLockManager(), ns_key);
+  std::optional<LockGuard> lock_guard;
+  if (spec.with_deletion) lock_guard.emplace(storage_->GetLockManager(), 
ns_key);
   ZSetMetadata metadata(false);
   rocksdb::Status s = GetMetadata(ns_key, &metadata);
   if (!s.ok()) return s.IsNotFound() ? rocksdb::Status::OK() : s;
@@ -433,9 +434,9 @@ rocksdb::Status ZSet::RangeByLex(const Slice &user_key, 
const RangeLexSpec &spec
   std::string ns_key;
   AppendNamespacePrefix(user_key, &ns_key);
 
-  std::unique_ptr<LockGuard> lock_guard;
+  std::optional<LockGuard> lock_guard;
   if (spec.with_deletion) {
-    lock_guard = std::make_unique<LockGuard>(storage_->GetLockManager(), 
ns_key);
+    lock_guard.emplace(storage_->GetLockManager(), ns_key);
   }
   ZSetMetadata metadata(false);
   rocksdb::Status s = GetMetadata(ns_key, &metadata);

Reply via email to