@@ -39,7 +39,7 @@ using namespace arangodb::aql;
39
39
static arangodb::aql::QueryCache Instance;
40
40
41
41
// / @brief maximum number of results in each per-database cache
42
- static size_t MaxResults = 128 ; // default value. can be changed later
42
+ static std::atomic< size_t > MaxResults ( 128 ) ; // default value. can be changed later
43
43
44
44
// / @brief whether or not the cache is enabled
45
45
static std::atomic<arangodb::aql::QueryCacheMode> Mode (CACHE_ON_DEMAND);
@@ -58,30 +58,6 @@ QueryCacheResultEntry::QueryCacheResultEntry(
58
58
_deletionRequested(0 ) {
59
59
}
60
60
61
- // / @brief check whether the element can be destroyed, and delete it if yes
62
- void QueryCacheResultEntry::tryDelete () {
63
- _deletionRequested = 1 ;
64
-
65
- if (_refCount == 0 ) {
66
- delete this ;
67
- }
68
- }
69
-
70
- // / @brief use the element, so it cannot be deleted meanwhile
71
- void QueryCacheResultEntry::use () { ++_refCount; }
72
-
73
- // / @brief unuse the element, so it can be deleted if required
74
- void QueryCacheResultEntry::unuse () {
75
- TRI_ASSERT (_refCount > 0 );
76
-
77
- if (--_refCount == 0 ) {
78
- if (_deletionRequested == 1 ) {
79
- // trigger the deletion
80
- delete this ;
81
- }
82
- }
83
- }
84
-
85
61
// / @brief create a database-specific cache
86
62
QueryCacheDatabaseEntry::QueryCacheDatabaseEntry ()
87
63
: _entriesByHash(),
@@ -95,16 +71,12 @@ QueryCacheDatabaseEntry::QueryCacheDatabaseEntry()
95
71
96
72
// / @brief destroy a database-specific cache
97
73
QueryCacheDatabaseEntry::~QueryCacheDatabaseEntry () {
98
- for (auto & it : _entriesByHash) {
99
- tryDelete (it.second );
100
- }
101
-
102
74
_entriesByHash.clear ();
103
75
_entriesByCollection.clear ();
104
76
}
105
77
106
78
// / @brief lookup a query result in the database-specific cache
107
- QueryCacheResultEntry* QueryCacheDatabaseEntry::lookup (
79
+ std::shared_ptr< QueryCacheResultEntry> QueryCacheDatabaseEntry::lookup (
108
80
uint64_t hash, QueryString const & queryString) {
109
81
auto it = _entriesByHash.find (hash);
110
82
@@ -123,26 +95,20 @@ QueryCacheResultEntry* QueryCacheDatabaseEntry::lookup(
123
95
}
124
96
125
97
// found an entry
126
- auto entry = (*it).second ;
127
-
128
- // mark the entry as being used so noone else can delete it while it is in use
129
- entry->use ();
130
-
131
- return entry;
98
+ return (*it).second ;
132
99
}
133
100
134
101
// / @brief store a query result in the database-specific cache
135
102
void QueryCacheDatabaseEntry::store (uint64_t hash,
136
- QueryCacheResultEntry* entry) {
103
+ std::shared_ptr< QueryCacheResultEntry> entry) {
137
104
// insert entry into the cache
138
105
if (!_entriesByHash.emplace (hash, entry).second ) {
139
106
// remove previous entry
140
107
auto it = _entriesByHash.find (hash);
141
108
TRI_ASSERT (it != _entriesByHash.end ());
142
109
auto previous = (*it).second ;
143
- unlink (previous);
110
+ unlink (previous. get () );
144
111
_entriesByHash.erase (it);
145
- tryDelete (previous);
146
112
147
113
// and insert again
148
114
_entriesByHash.emplace (hash, entry);
@@ -177,19 +143,19 @@ void QueryCacheDatabaseEntry::store(uint64_t hash,
177
143
TRI_ASSERT (it != _entriesByHash.end ());
178
144
auto previous = (*it).second ;
179
145
_entriesByHash.erase (it);
180
- unlink (previous);
181
- tryDelete (previous);
146
+ unlink (previous.get ());
182
147
throw ;
183
148
}
184
149
185
- link (entry);
150
+ link (entry. get () );
186
151
187
- enforceMaxResults (MaxResults);
152
+ size_t maxResults = MaxResults.load ();
153
+ enforceMaxResults (maxResults);
188
154
189
- TRI_ASSERT (_numElements <= MaxResults );
155
+ TRI_ASSERT (_numElements <= maxResults );
190
156
TRI_ASSERT (_head != nullptr );
191
157
TRI_ASSERT (_tail != nullptr );
192
- TRI_ASSERT (_tail == entry);
158
+ TRI_ASSERT (_tail == entry. get () );
193
159
TRI_ASSERT (entry->_next == nullptr );
194
160
}
195
161
@@ -217,13 +183,10 @@ void QueryCacheDatabaseEntry::invalidate(std::string const& collection) {
217
183
if (it3 != _entriesByHash.end ()) {
218
184
// remove entry from the linked list
219
185
auto entry = (*it3).second ;
220
- unlink (entry);
186
+ unlink (entry. get () );
221
187
222
188
// erase it from hash table
223
189
_entriesByHash.erase (it3);
224
-
225
- // delete the object itself
226
- tryDelete (entry);
227
190
}
228
191
}
229
192
@@ -241,15 +204,9 @@ void QueryCacheDatabaseEntry::enforceMaxResults(size_t value) {
241
204
auto it = _entriesByHash.find (head->_hash );
242
205
TRI_ASSERT (it != _entriesByHash.end ());
243
206
_entriesByHash.erase (it);
244
- tryDelete (head);
245
207
}
246
208
}
247
209
248
- // / @brief check whether the element can be destroyed, and delete it if yes
249
- void QueryCacheDatabaseEntry::tryDelete (QueryCacheResultEntry* e) {
250
- e->tryDelete ();
251
- }
252
-
253
210
// / @brief unlink the result entry from the list
254
211
void QueryCacheDatabaseEntry::unlink (QueryCacheResultEntry* e) {
255
212
if (e->_prev != nullptr ) {
@@ -312,7 +269,7 @@ VPackBuilder QueryCache::properties() {
312
269
VPackBuilder builder;
313
270
builder.openObject ();
314
271
builder.add (" mode" , VPackValue (modeString (mode ())));
315
- builder.add (" maxResults" , VPackValue (MaxResults));
272
+ builder.add (" maxResults" , VPackValue (MaxResults. load () ));
316
273
builder.close ();
317
274
318
275
return builder;
@@ -323,7 +280,7 @@ void QueryCache::properties(std::pair<std::string, size_t>& result) {
323
280
MUTEX_LOCKER (mutexLocker, _propertiesLock);
324
281
325
282
result.first = modeString (mode ());
326
- result.second = MaxResults;
283
+ result.second = MaxResults. load () ;
327
284
}
328
285
329
286
// / @brief set the cache properties
@@ -361,8 +318,8 @@ std::string QueryCache::modeString(QueryCacheMode mode) {
361
318
}
362
319
363
320
// / @brief lookup a query result in the cache
364
- QueryCacheResultEntry* QueryCache::lookup (TRI_vocbase_t* vocbase, uint64_t hash,
365
- QueryString const & queryString) {
321
+ std::shared_ptr< QueryCacheResultEntry> QueryCache::lookup (TRI_vocbase_t* vocbase, uint64_t hash,
322
+ QueryString const & queryString) {
366
323
auto const part = getPart (vocbase);
367
324
READ_LOCKER (readLocker, _entriesLock[part]);
368
325
@@ -379,7 +336,7 @@ QueryCacheResultEntry* QueryCache::lookup(TRI_vocbase_t* vocbase, uint64_t hash,
379
336
// / @brief store a query in the cache
380
337
// / if the call is successful, the cache has taken over ownership for the
381
338
// / query result!
382
- QueryCacheResultEntry* QueryCache::store (
339
+ std::shared_ptr< QueryCacheResultEntry> QueryCache::store (
383
340
TRI_vocbase_t* vocbase, uint64_t hash, QueryString const & queryString,
384
341
std::shared_ptr<VPackBuilder> result,
385
342
std::vector<std::string> const & collections) {
@@ -392,7 +349,7 @@ QueryCacheResultEntry* QueryCache::store(
392
349
auto const part = getPart (vocbase);
393
350
394
351
// create the cache entry outside the lock
395
- auto entry = std::make_unique <QueryCacheResultEntry>(
352
+ auto entry = std::make_shared <QueryCacheResultEntry>(
396
353
hash, queryString, result, collections);
397
354
398
355
WRITE_LOCKER (writeLocker, _entriesLock[part]);
@@ -407,8 +364,8 @@ QueryCacheResultEntry* QueryCache::store(
407
364
}
408
365
409
366
// store cache entry
410
- (*it).second ->store (hash, entry. get () );
411
- return entry. release () ;
367
+ (*it).second ->store (hash, entry);
368
+ return entry;
412
369
}
413
370
414
371
// / @brief invalidate all queries for the given collections
@@ -512,16 +469,19 @@ void QueryCache::invalidate(unsigned int part) {
512
469
}
513
470
514
471
// / @brief sets the maximum number of results in each per-database cache
472
+ // / is called under the mutex
515
473
void QueryCache::setMaxResults (size_t value) {
516
474
if (value == 0 ) {
517
475
return ;
518
476
}
519
477
520
- if (value > MaxResults) {
478
+ size_t maxResults = MaxResults.load ();
479
+
480
+ if (value > maxResults) {
521
481
enforceMaxResults (value);
522
482
}
523
483
524
- MaxResults = value;
484
+ maxResults = value;
525
485
}
526
486
527
487
// / @brief sets the caching mode
0 commit comments