bes  Updated for version 3.20.6
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 <DapObj.h>
35 #include <InternalErr.h>
36 
37 #include "ObjMemCache.h"
38 
39 // using namespace bes {
40 
41 using namespace std;
42 using namespace libdap;
43 
44 ObjMemCache::~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 
63 void 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 
85 void 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 
105 DapObj *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 
145 void 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
ObjMemCache::purge
virtual void purge(float fraction)
Purge the oldest elements.
Definition: ObjMemCache.cc:145
ObjMemCache::add
virtual void add(libdap::DapObj *obj, const std::string &key)
Add an object to the cache and associate it with a key.
Definition: ObjMemCache.cc:63
libdap
Definition: BESDapFunctionResponseCache.h:35
ObjMemCache::remove
virtual void remove(const std::string &key)
Remove the object associated with a key.
Definition: ObjMemCache.cc:85
ObjMemCache::get
virtual libdap::DapObj * get(const std::string &key)
Get the cached pointer.
Definition: ObjMemCache.cc:105