1/**
2 * Copyright 2021 Alibaba, Inc. and its affiliates. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15
16 * \author Haichao.chc
17 * \date Oct 2020
18 * \brief Concurrent hashmap which is thread-safe for add/del operations
19 */
20
21#pragma once
22
23#include <unordered_map>
24#include <ailego/parallel/lock.h>
25
26namespace proxima {
27namespace be {
28namespace index {
29
30/*
31 * Concurrent hash map for synchronously get/set item.
32 */
33template <typename TKey, typename TValue>
34class ConcurrentHashMap {
35 public:
36 //! Constructor
37 ConcurrentHashMap() = default;
38
39 //! Destructor
40 ~ConcurrentHashMap() = default;
41
42 public:
43 //! Emplace a key-value pair
44 void emplace(TKey key, TValue val) {
45 rw_lock_.lock();
46 map_.emplace(key, val);
47 rw_lock_.unlock();
48 }
49
50 //! Get value by key
51 const TValue &get(TKey key) const {
52 rw_lock_.lock_shared();
53 const TValue &val = map_.at(key);
54 rw_lock_.unlock_shared();
55 return val;
56 }
57
58 //! If has key
59 bool has(TKey key) const {
60 bool found = false;
61 rw_lock_.lock_shared();
62 if (map_.find(key) != map_.end()) {
63 found = true;
64 }
65 rw_lock_.unlock_shared();
66 return found;
67 }
68
69 //! Return key-value pair count
70 size_t size() const {
71 size_t val;
72 rw_lock_.lock_shared();
73 val = map_.size();
74 rw_lock_.unlock_shared();
75 return val;
76 }
77
78 //! Erase a pair by key
79 void erase(TKey key) {
80 rw_lock_.lock();
81 map_.erase(key);
82 rw_lock_.unlock();
83 }
84
85 //! Clear all pairs
86 void clear() {
87 rw_lock_.lock();
88 map_.clear();
89 rw_lock_.unlock();
90 }
91
92 typedef typename std::unordered_map<TKey, TValue>::iterator iterator;
93 typedef
94 typename std::unordered_map<TKey, TValue>::const_iterator const_iterator;
95
96 // NOTICE: iterator interface is only called when
97 // uppper class destruct, and ensure in single thread
98 //
99 // Return begin iterator
100 iterator begin() {
101 rw_lock_.lock_shared();
102 iterator it = map_.begin();
103 rw_lock_.unlock_shared();
104 return it;
105 }
106
107 //! Return const begin iterator
108 const_iterator begin() const {
109 rw_lock_.lock_shared();
110 const_iterator it = map_.begin();
111 rw_lock_.unlock_shared();
112 return it;
113 }
114
115 //! Return reverse begin iterator
116 const_iterator cbegin() const {
117 rw_lock_.lock_shared();
118 const_iterator it = map_.cbegin();
119 rw_lock_.unlock_shared();
120 return it;
121 }
122
123 //! Return end iterator
124 iterator end() {
125 rw_lock_.lock_shared();
126 iterator it = map_.end();
127 rw_lock_.unlock_shared();
128 return it;
129 }
130
131 //! Return const end iterator
132 const_iterator end() const {
133 rw_lock_.lock_shared();
134 const_iterator it = map_.end();
135 rw_lock_.unlock_shared();
136 return it;
137 }
138
139 //! Return cend iterator
140 const_iterator cend() const {
141 rw_lock_.lock_shared();
142 const_iterator it = map_.cend();
143 rw_lock_.unlock_shared();
144 return it;
145 }
146
147 private:
148 mutable ailego::SharedMutex rw_lock_{};
149 std::unordered_map<TKey, TValue> map_{};
150};
151
152
153} // end namespace index
154} // namespace be
155} // end namespace proxima
156