bes Updated for version 3.21.1
The Backend Server (BES) is the lower two tiers of the Hyrax data server
ObjMemCache.cc
1// This file is part of bes, A C++ back-end server implementation framework
2// for the OPeNDAP Data Access Protocol.
3
4// Copyright (c) 2016 OPeNDAP
5// Author: James Gallagher <jgallagher@opendap.org>
6//
7// This library is free software; you can redistribute it and/or
8// modify it under the terms of the GNU Lesser General Public
9// License as published by the Free Software Foundation; either
10// version 2.1 of the License, or (at your option) any later version.
11//
12// This library is distributed in the hope that it will be useful,
13// but WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15// Lesser General Public License for more details.
16//
17// You should have received a copy of the GNU Lesser General Public
18// License along with this library; if not, write to the Free Software
19// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
21/*
22 * ObjMemCache.cc
23 *
24 * Created on: May 18, 2016
25 * Author: jimg
26 */
27
28
29#include "config.h"
30
31#include <string>
32#include <map>
33
34#include <libdap/DapObj.h>
35#include <libdap/InternalErr.h>
36
37#include "ObjMemCache.h"
38
39// using namespace bes {
40
41using namespace std;
42using namespace libdap;
43
44ObjMemCache::~ObjMemCache()
45{
46 for (cache_t::iterator i = cache.begin(), e = cache.end(); i != e; ++i) {
47 assert(i->second);
48 delete i->second;
49 }
50}
51
63void ObjMemCache::add(DapObj *obj, const string &key)
64{
65 ++d_age;
66
67 // if d_entries_threshold is zero, the caller handles calling
68 // purge.
69 //
70 // Bug fix: was using 'd_age > d_entries_threshold' which didn't
71 // work so I switched to the cache.size(). This is a fix for Hyrax-270.
72 // jhrg 10/21/16
73 if (d_entries_threshold && (cache.size() > d_entries_threshold))
74 purge(d_purge_threshold);
75
76 index.insert(index_pair_t(key, d_age));
77
78 cache.insert(cache_pair_t(d_age, new Entry(obj, key)));
79}
80
85void ObjMemCache::remove(const string &key)
86{
87 index_t::iterator i = index.find(key);
88
89 if (i != index.end()) {
90 unsigned int count = i->second;
91 index.erase(i);
92 cache_t::iterator c = cache.find(count);
93 assert(c != cache.end());
94 assert(c->second); // should never cache a null ptr
95 delete c->second; // delete the Entry*, but not the contained obj*
96 cache.erase(c);
97 }
98}
99
105DapObj *ObjMemCache::get(const string &key)
106{
107 DapObj *cached_obj = 0;
108
109 index_t::iterator i = index.find(key);
110 if (i != index.end()) {
111 cache_t::iterator c = cache.find(i->second);
112 assert(c != cache.end());
113 // leave this second test in, but unless the cache is
114 // broken, it should never be false.
115 if (c != cache.end()) {
116 assert(c->second);
117 // get the Entry and the DDS
118 Entry *e = c->second;
119 cached_obj = e->d_obj; // cached_obj == the return value
120
121 // now erase & reinsert the pair
122 cache.erase(c);
123 cache.insert(cache_pair_t(++d_age, e));
124 }
125 else {
126 // I'm leaving the test and this exception in because getting
127 // a bad DDS will lead to a bug that is hard to figure out. Other
128 // parts of the code I'm assuming assert() calls are good enough.
129 // jhrg 5/20/16
130 throw InternalErr(__FILE__, __LINE__, "Memory cache consistency error.");
131 }
132
133 // update the index
134 index.erase(i);
135 index.insert(index_pair_t(key, d_age));
136 }
137
138 return cached_obj;
139}
140
145void ObjMemCache::purge(float fraction)
146{
147 // Map are ordered using less by default, so the oldest entries are first
148 size_t num_remove = cache.size() * fraction;
149
150 cache_t::iterator c = cache.begin(), e = cache.end();
151 for (unsigned int i = 0; i < num_remove && c != e; ++i) {
152 const string name = c->second->d_name;
153 delete c->second; // deletes the Entry, not the obj that its internals point to
154 cache.erase(c);
155 c = cache.begin(); // erase() invalidates the iterator
156
157 index_t::iterator pos = index.find(name);
158 assert(pos != index.end());
159 index.erase(pos);
160 }
161}
162
163// } namespace bes
virtual void add(libdap::DapObj *obj, const std::string &key)
Add an object to the cache and associate it with a key.
virtual libdap::DapObj * get(const std::string &key)
Get the cached pointer.
virtual void remove(const std::string &key)
Remove the object associated with a key.
virtual void purge(float fraction)
Purge the oldest elements.