forked from jimmybergman/powerdns
/
cachecleaner.hh
83 lines (64 loc) · 2.46 KB
/
cachecleaner.hh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#ifndef PDNS_CACHECLEANER_HH
#define PDNS_CACHECLEANER_HH
// this function can clean any cache that has a getTTD() method on its entries, and a 'sequence' index as its second index
// the ritual is that the oldest entries are in *front* of the sequence collection, so on a hit, move an item to the end
// on a miss, move it to the beginning
template <typename T> void pruneCollection(T& collection, unsigned int maxCached, unsigned int scanFraction=1000)
{
uint32_t now=(uint32_t)time(0);
unsigned int toTrim=0;
unsigned int cacheSize=collection.size();
if(cacheSize > maxCached) {
toTrim = cacheSize - maxCached;
}
// cout<<"Need to trim "<<toTrim<<" from cache to meet target!\n";
typedef typename T::template nth_index<1>::type sequence_t;
sequence_t& sidx=collection.template get<1>();
unsigned int tried=0, lookAt, erased=0;
// two modes - if toTrim is 0, just look through 1/scanFraction of all records
// and nuke everything that is expired
// otherwise, scan first 5*toTrim records, and stop once we've nuked enough
if(toTrim)
lookAt=5*toTrim;
else
lookAt=cacheSize/scanFraction;
typename sequence_t::iterator iter=sidx.begin(), eiter;
for(; iter != sidx.end() && tried < lookAt ; ++tried) {
if(iter->getTTD() < now) {
sidx.erase(iter++);
erased++;
}
else
++iter;
if(toTrim && erased > toTrim)
break;
}
//cout<<"erased "<<erased<<" records based on ttd\n";
if(erased >= toTrim) // done
return;
toTrim -= erased;
//if(toTrim)
// cout<<"Still have "<<toTrim - erased<<" entries left to erase to meet target\n";
eiter=iter=sidx.begin();
std::advance(eiter, toTrim);
sidx.erase(iter, eiter); // just lob it off from the beginning
}
template <typename T> void moveCacheItemToFrontOrBack(T& collection, typename T::iterator& iter, bool front)
{
typedef typename T::template nth_index<1>::type sequence_t;
sequence_t& sidx=collection.template get<1>();
typename sequence_t::iterator si=collection.template project<1>(iter);
if(front)
sidx.relocate(sidx.begin(), si); // at the beginning of the delete queue
else
sidx.relocate(sidx.end(), si); // back
}
template <typename T> void moveCacheItemToFront(T& collection, typename T::iterator& iter)
{
moveCacheItemToFrontOrBack(collection, iter, true);
}
template <typename T> void moveCacheItemToBack(T& collection, typename T::iterator& iter)
{
moveCacheItemToFrontOrBack(collection, iter, false);
}
#endif