@@ -39,93 +39,108 @@ namespace backend {
39
39
40
40
InMemoryPerProcess::InMemoryPerProcess (const std::string &name) :
41
41
Collection (name) {
42
- this ->reserve (1000 );
43
- pthread_mutex_init (&m_lock, NULL );
42
+ m_map.reserve (1000 );
44
43
}
45
44
46
45
InMemoryPerProcess::~InMemoryPerProcess () {
47
- this ->clear ();
48
- pthread_mutex_destroy (&m_lock);
46
+ m_map.clear ();
49
47
}
50
48
51
- void InMemoryPerProcess::store (std::string key, std::string value) {
52
- pthread_mutex_lock (&m_lock);
53
- this ->emplace (key, value);
54
- pthread_mutex_unlock (&m_lock);
55
- }
56
49
50
+ template <typename Map>
51
+ inline void __store (Map &map, std::string key, std::string value) {
52
+ // NOTE: should be called with write-lock previously acquired
57
53
58
- bool InMemoryPerProcess::storeOrUpdateFirst (const std::string &key,
59
- const std::string &value) {
60
- if (updateFirst (key, value) == false ) {
61
- store (key, value);
62
- }
63
- return true ;
54
+ map.emplace (key, value);
64
55
}
65
56
66
57
67
- bool InMemoryPerProcess::updateFirst (const std::string &key,
58
+ template <typename Map>
59
+ inline bool __updateFirst (Map &map,
60
+ const std::string &key,
68
61
const std::string &value) {
69
- pthread_mutex_lock (&m_lock);
62
+ // NOTE: should be called with write-lock previously acquired
70
63
71
- if (auto search = this -> find (key); search != this -> end ()) {
64
+ if (auto search = map. find (key); search != map. end ()) {
72
65
search->second .setValue (value);
73
- pthread_mutex_unlock (&m_lock);
74
66
return true ;
75
67
}
76
68
77
- pthread_mutex_unlock (&m_lock);
78
69
return false ;
79
70
}
80
71
81
72
73
+ void InMemoryPerProcess::store (const std::string &key, const std::string &value) {
74
+ const std::lock_guard lock (m_mutex); // write lock (exclusive access)
75
+ __store (m_map, key, value);
76
+ }
77
+
78
+
79
+ bool InMemoryPerProcess::storeOrUpdateFirst (const std::string &key,
80
+ const std::string &value) {
81
+ const std::lock_guard lock (m_mutex); // write lock (exclusive access)
82
+ if (__updateFirst (m_map, key, value) == false ) {
83
+ __store (m_map, key, value);
84
+ }
85
+ return true ;
86
+ }
87
+
88
+
89
+ bool InMemoryPerProcess::updateFirst (const std::string &key,
90
+ const std::string &value) {
91
+ const std::lock_guard lock (m_mutex); // write lock (exclusive access)
92
+ return __updateFirst (m_map, key, value);
93
+ }
94
+
95
+
82
96
void InMemoryPerProcess::del (const std::string& key) {
83
- pthread_mutex_lock (&m_lock);
84
- this ->erase (key);
85
- pthread_mutex_unlock (&m_lock);
97
+ const std::lock_guard lock (m_mutex); // write lock (exclusive access)
98
+ m_map.erase (key);
86
99
}
87
100
88
101
void InMemoryPerProcess::delIfExpired (const std::string& key) {
89
- pthread_mutex_lock (&m_lock);
102
+ const std::lock_guard lock (m_mutex); // write lock (exclusive access)
90
103
// Double check the status while within the mutex
91
- auto iter = this ->find (key);
92
- if ((iter != this ->end ()) && (iter->second .isExpired ())) {
93
- this ->erase (key);
104
+ const auto iter = std::find_if (m_map.begin (), m_map.end (),
105
+ [&key](const auto &x) { return x.first == key && x.second .isExpired (); });
106
+ if (iter != m_map.end ()) {
107
+ m_map.erase (key);
94
108
}
95
- pthread_mutex_unlock (&m_lock);
96
109
}
97
110
98
111
void InMemoryPerProcess::setExpiry (const std::string& key, int32_t expiry_seconds) {
99
- pthread_mutex_lock (&m_lock);
112
+ const std::lock_guard lock (m_mutex); // write lock (exclusive access)
100
113
101
- if (auto search = this -> find (key); search != this -> end ()) {
114
+ if (const auto search = m_map. find (key); search != m_map. end ()) {
102
115
search->second .setExpiry (expiry_seconds);
103
- pthread_mutex_unlock (&m_lock);
104
116
return ;
105
117
}
106
118
107
119
// We allow an expiry value to be set for a key that has not (yet) had a value set.
108
- auto iter = this -> emplace (key, CollectionData ());
120
+ const auto iter = m_map. emplace (key, CollectionData ());
109
121
iter->second .setExpiry (expiry_seconds);
110
-
111
- pthread_mutex_unlock (&m_lock);
112
122
}
113
123
114
124
115
125
void InMemoryPerProcess::resolveSingleMatch (const std::string& var,
116
126
std::vector<const VariableValue *> *l) {
117
127
std::list<std::string> expiredVars;
118
- auto range = this ->equal_range (var);
119
-
120
- for (auto it = range.first ; it != range.second ; ++it) {
121
- if (it->second .isExpired ()) {
122
- expiredVars.push_back (it->first );
123
- } else if (it->second .hasValue () == false ) {
124
- // No-op. A non-expired expiry exists for the key but there is no actual value
125
- } else {
126
- l->push_back (new VariableValue (&m_name, &it->first , &it->second .getValue ()));
127
- }
128
+
129
+ {
130
+ const std::shared_lock lock (m_mutex); // read lock (shared access)
131
+
132
+ const auto range = m_map.equal_range (var);
133
+ for (auto it = range.first ; it != range.second ; ++it) {
134
+ if (it->second .isExpired ()) {
135
+ expiredVars.push_back (it->first );
136
+ } else if (it->second .hasValue () == false ) {
137
+ // No-op. A non-expired expiry exists for the key but there is no actual value
138
+ } else {
139
+ l->push_back (new VariableValue (&m_name, &it->first , &it->second .getValue ()));
140
+ }
141
+ }
128
142
}
143
+
129
144
for (const auto & expiredVar : expiredVars) {
130
145
delIfExpired (expiredVar);
131
146
}
@@ -134,40 +149,45 @@ void InMemoryPerProcess::resolveSingleMatch(const std::string& var,
134
149
135
150
void InMemoryPerProcess::resolveMultiMatches (const std::string& var,
136
151
std::vector<const VariableValue *> *l, variables::KeyExclusions &ke) {
137
- size_t keySize = var.size ();
152
+ const auto keySize = var.size ();
138
153
l->reserve (15 );
139
154
std::list<std::string> expiredVars;
140
155
141
- if (keySize == 0 ) {
142
- for (auto &i : *this ) {
143
- if (ke.toOmit (i.first )) {
144
- continue ;
156
+ {
157
+ const std::shared_lock lock (m_mutex); // read lock (shared access)
158
+
159
+ if (keySize == 0 ) {
160
+ for (auto &i : m_map) {
161
+ if (ke.toOmit (i.first )) {
162
+ continue ;
163
+ }
164
+ if (i.second .isExpired ()) {
165
+ expiredVars.push_back (i.first );
166
+ } else if (i.second .hasValue () == false ) {
167
+ // No-op. A non-expired expiry exists for the key but there is no actual value
168
+ } else {
169
+ l->insert (l->begin (), new VariableValue (&m_name, &i.first ,
170
+ &i.second .getValue ()));
171
+ }
145
172
}
146
- if (i. second . isExpired ()) {
147
- expiredVars. push_back (i. first );
148
- } else if (i. second . hasValue () == false ) {
149
- // No-op. A non-expired expiry exists for the key but there is no actual value
150
- } else {
151
- l-> insert (l-> begin (), new VariableValue (&m_name, &i. first ,
152
- &i. second .getValue ()));
153
- }
154
- }
155
- } else {
156
- auto range = this -> equal_range (var);
157
- for ( auto it = range. first ; it != range. second ; ++it) {
158
- if (ke. toOmit (var)) {
159
- continue ;
173
+ } else {
174
+ const auto range = m_map. equal_range (var );
175
+ for ( auto it = range. first ; it != range. second ; ++it ) {
176
+ if (ke. toOmit (var)) {
177
+ continue ;
178
+ }
179
+ if (it-> second .isExpired ()) {
180
+ expiredVars. push_back (it-> first );
181
+ } else if (it-> second . hasValue () == false ) {
182
+ // No-op. A non-expired expiry exists for the key but there is no actual value
183
+ } else {
184
+ l-> insert (l-> begin (), new VariableValue (&m_name, &var,
185
+ &it-> second . getValue ()));
186
+ }
160
187
}
161
- if (it->second .isExpired ()) {
162
- expiredVars.push_back (it->first );
163
- } else if (it->second .hasValue () == false ) {
164
- // No-op. A non-expired expiry exists for the key but there is no actual value
165
- } else {
166
- l->insert (l->begin (), new VariableValue (&m_name, &var,
167
- &it->second .getValue ()));
168
- }
169
188
}
170
189
}
190
+
171
191
for (const auto & expiredVar : expiredVars) {
172
192
delIfExpired (expiredVar);
173
193
}
@@ -176,47 +196,30 @@ void InMemoryPerProcess::resolveMultiMatches(const std::string& var,
176
196
177
197
void InMemoryPerProcess::resolveRegularExpression (const std::string& var,
178
198
std::vector<const VariableValue *> *l, variables::KeyExclusions &ke) {
179
-
180
- // if (var.find(":") == std::string::npos) {
181
- // return;
182
- // }
183
- // if (var.size() < var.find(":") + 3) {
184
- // return;
185
- // }
186
- // std::string col = std::string(var, 0, var.find(":"));
187
- // std::string name = std::string(var, var.find(":") + 2,
188
- // var.size() - var.find(":") - 3);
189
- // size_t keySize = col.size();
190
199
Utils::Regex r (var, true );
191
200
std::list<std::string> expiredVars;
192
201
193
- for ( const auto & x : * this ) {
194
- // if (x.first.size() <= keySize + 1) {
195
- // continue;
196
- // }
197
- // if (x.first.at(keySize) != ':') {
198
- // continue;
199
- // }
200
- // if (std::string(x.first, 0, keySize) != col) {
201
- // continue;
202
- // }
203
- // std::string content = std::string(x.first, keySize + 1,
204
- // x.first.size() - keySize - 1);
205
- int ret = Utils::regex_search (x.first , r );
206
- if (ret <= 0 ) {
207
- continue ;
208
- }
209
- if (ke. toOmit ( x.first )) {
210
- continue ;
202
+ {
203
+ const std::shared_lock lock (m_mutex); // read lock (shared access)
204
+
205
+ for ( const auto & x : m_map) {
206
+ const auto ret = Utils::regex_search (x.first , r);
207
+ if (ret <= 0 ) {
208
+ continue ;
209
+ }
210
+ if (ke. toOmit (x. first )) {
211
+ continue ;
212
+ }
213
+ if (x. second . isExpired ()) {
214
+ expiredVars. push_back (x.first );
215
+ } else if (x. second . hasValue () == false ) {
216
+ // No-op. A non-expired expiry exists for the key but there is no actual value
217
+ } else {
218
+ l-> insert (l-> begin (), new VariableValue (&m_name, & x.first , &x. second . getValue ()));
219
+ }
211
220
}
212
- if (x.second .isExpired ()) {
213
- expiredVars.push_back (x.first );
214
- } else if (x.second .hasValue () == false ) {
215
- // No-op. A non-expired expiry exists for the key but there is no actual value
216
- } else {
217
- l->insert (l->begin (), new VariableValue (&m_name, &x.first , &x.second .getValue ()));
218
- }
219
221
}
222
+
220
223
for (const auto & expiredVar : expiredVars) {
221
224
delIfExpired (expiredVar);
222
225
}
@@ -225,18 +228,29 @@ void InMemoryPerProcess::resolveRegularExpression(const std::string& var,
225
228
226
229
std::unique_ptr<std::string> InMemoryPerProcess::resolveFirst (
227
230
const std::string& var) {
228
- auto range = equal_range (var);
229
- for (auto it = range.first ; it != range.second ; ++it) {
230
- if (it->second .isExpired ()) {
231
- delIfExpired (it->second .getValue ());
232
- } else if (it->second .hasValue () == false ) {
233
- // No-op. A non-expired expiry exists for the key but there is no actual value
234
- } else {
235
- return std::unique_ptr<std::string>(new std::string (it->second .getValue ()));
236
- }
231
+ std::unique_ptr<std::string> ret;
232
+ std::list<std::string> expiredVars;
233
+
234
+ {
235
+ const std::shared_lock lock (m_mutex); // read lock (shared access)
236
+
237
+ const auto range = m_map.equal_range (var);
238
+ for (auto it = range.first ; it != range.second ; ++it) {
239
+ if (it->second .isExpired ()) {
240
+ expiredVars.push_back (it->first );
241
+ } else if (it->second .hasValue () == false ) {
242
+ // No-op. A non-expired expiry exists for the key but there is no actual value
243
+ } else {
244
+ ret = std::make_unique<std::string>(it->second .getValue ());
245
+ }
246
+ }
247
+ }
248
+
249
+ for (const auto & expiredVar : expiredVars) {
250
+ delIfExpired (expiredVar);
237
251
}
238
252
239
- return NULL ;
253
+ return ret ;
240
254
}
241
255
242
256
0 commit comments