libjmmcg  release_579_6_g8cffd
A C++ library containing an eclectic mix of useful, advanced components.
cache_impl.hpp
Go to the documentation of this file.
1 /******************************************************************************
2 ** Copyright © 2005 by J.M.McGuiness, coder@hussar.me.uk
3 **
4 ** This library is free software; you can redistribute it and/or
5 ** modify it under the terms of the GNU Lesser General Public
6 ** License as published by the Free Software Foundation; either
7 ** version 2.1 of the License, or (at your option) any later version.
8 **
9 ** This library is distributed in the hope that it will be useful,
10 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 ** Lesser General Public License for more details.
13 **
14 ** You should have received a copy of the GNU Lesser General Public
15 ** License along with this library; if not, write to the Free Software
16 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18 
19 namespace jmmcg { namespace LIBJMMCG_VER_NAMESPACE { namespace cache {
20 
21  template<typename Val_> inline constexpr
22  lru<Val_>::lru(void)
23  : age(),range_value() {
24  }
25 
26  template<typename Val_> inline constexpr
27  lru<Val_>::lru(const value_type &v)
28  : age(),range_value(v) {
29  }
30 
31  template<typename Val_> inline
32  lru<Val_>::lru(const lru &l)
33  : age(l.age),range_value(l.range_value) {
34  }
35 
36  template<typename Val_> inline
37  lru<Val_>::~lru(void) {
38  }
39 
40  template<typename Val_> inline lru<Val_> &
41  lru<Val_>::operator=(const lru &l) {
42  age=l.age;
43  range_value=l.range_value;
44  return *this;
45  }
46 
47  template<typename Val_> inline const typename lru<Val_>::value_type &
48  lru<Val_>::value(void) const noexcept(true) {
49  age=clock();
50  return range_value;
51  }
52 
53  template<typename Val_> inline typename lru<Val_>::value_type &
54  lru<Val_>::value(void) noexcept(true) {
55  age=clock();
56  return range_value;
57  }
58 
59  template<typename Val_> inline clock_t
60  lru<Val_>::accessed(void) const noexcept(true) {
61  return age;
62  }
63 
64  inline constexpr
65  basic_statistics::basic_statistics(void) noexcept(true)
66  : total_accesses_(),total_hits_(),total_flushes_() {
67  }
68 
69  inline
71  : total_accesses_(bs.total_accesses_),total_hits_(bs.total_hits_),total_flushes_(bs.total_flushes_) {
72  }
73 
74  inline
75  basic_statistics::~basic_statistics(void) noexcept(true) {
76  }
77 
78  inline basic_statistics &
79  basic_statistics::operator=(const basic_statistics &bs)noexcept(true) {
80  total_accesses_=bs.total_accesses_;
81  total_hits_=bs.total_hits_;
82  total_flushes_=bs.total_flushes_;
83  return *this;
84  }
85 
87  basic_statistics::accesses(void) const noexcept(true) {
88  return total_accesses_;
89  }
90 
92  basic_statistics::hits(void) const noexcept(true) {
93  return total_hits_;
94  }
95 
97  basic_statistics::flushes(void) const noexcept(true) {
98  return total_flushes_;
99  }
100 
102  basic_statistics::outstanding_fills(void) const noexcept(true) {
103 ///\todo JMG need to compute this.
104  return 0;
105  }
106 
107  /**
108  \todo Implement using the advice given in "Standard C++ IOStreams and Locales" by A.Langer & K.Kreft, page 170.
109  */
110  inline tostream &
111  operator<<(tostream &os, const basic_statistics &stats) {
112  return os<<
113  _T("Basic cache statistics:\n")
114  _T("\tHit rate=")<<(static_cast<double>(stats.total_hits_)/stats.total_accesses_)<<_T("\n")
115  _T("\tTotal number of accesses=")<<stats.total_accesses_<<_T("\n")
116  _T("\tTotal number of hits=")<<stats.total_hits_<<_T("\n")
117  _T("\tTotal number of flushes=")<<stats.total_flushes_<<_T("\n")
118  _T("\tTotal number of current, outstanding fills=")<<stats.outstanding_fills()<<std::endl;
119  }
120 
121  inline void
122  basic_statistics::accessed(void) noexcept(true) {
123  ++total_accesses_;
124  }
125 
126  inline void
127  basic_statistics::hit(void) noexcept(true) {
128  ++total_hits_;
129  }
130 
131  inline void
132  basic_statistics::flushed(void) noexcept(true) {
133  ++total_flushes_;
134  }
135 
136  inline void
137  basic_statistics::reset(void) noexcept(true) {
138  total_accesses_=0;
139  total_hits_=0;
140  total_flushes_=0;
141  }
142 
143  template<class Factory> inline
144  base<Factory>::base(const base &r)
145  : data_factory_(r.data_factory_) {
146  }
147 
148  template<class Factory> inline
149  base<Factory>::~base(void) noexcept(true) {
150  }
151 
152  template<class Factory> inline base<Factory> &
153  base<Factory>::operator=(const base &r) {
154  data_factory_=r.data_factory_;
155  return *this;
156  }
157 
158  template<class Factory> inline const typename base<Factory>::factory_type &
159  base<Factory>::data_factory(void) const noexcept(true) {
160  return data_factory_;
161  }
162 
163  template<class Factory, class FP, class ThrT, class Stats> inline
164  ro<Factory, FP, ThrT, Stats>::ro(const ro &r)
165  : base<Factory>(r), low_water_mark(r.low_water_mark), high_water_mark(r.high_water_mark), serialize(), flusher_pool(), populate_pool(r.populate_pool.pool_size()), internal_cache(), statistics_(r.statistics_) {
166  const lock_t lock(r.serialize);
167  internal_cache=r.internal_cache;
168  }
169 
170  template<class Factory, class FP, class ThrT, class Stats> inline
171  ro<Factory, FP, ThrT, Stats>::~ro(void) noexcept(true) {
172  }
173 
174  template<class Factory, class FP, class ThrT, class Stats> inline ro<Factory, FP, ThrT, Stats> &
175  ro<Factory, FP, ThrT, Stats>::operator=(const ro &r) {
176  const lock_t lock_this(serialize,lock_traits::infinite_timeout());
177  base<Factory>::operator=(r);
178  low_water_mark=r.low_water_mark;
179  high_water_mark=r.high_water_mark;
180  internal_cache.reserve(low_water_mark);
181  const lock_t lock_that(r.serialize,lock_traits::infinite_timeout());
182  internal_cache=r.internal_cache;
183  statistics_=r.statistics_;
184  return *this;
185  }
186 
187  template<class Factory, class FP, class ThrT, class Stats> inline bool
188  ro<Factory, FP, ThrT, Stats>::empty(void) const noexcept(true) {
189  const lock_t lock(serialize,lock_traits::infinite_timeout());
190  return internal_cache.empty();
191  }
192 
193  template<class Factory, class FP, class ThrT, class Stats> inline const typename ro<Factory, FP, ThrT, Stats>::size_type
194  ro<Factory, FP, ThrT, Stats>::size(void) const noexcept(true) {
195  const lock_t lock(serialize,lock_traits::infinite_timeout());
196  return internal_cache.size();
197  }
198 
199  template<class Factory, class FP, class ThrT, class Stats> inline void
200  ro<Factory, FP, ThrT, Stats>::clear(void) {
201  const lock_t lock(serialize,lock_traits::infinite_timeout());
202  internal_cache.clear();
203  statistics_.reset();
204  }
205 
206  template<class Factory, class FP, class ThrT, class Stats> inline const typename ro<Factory, FP, ThrT, Stats>::mapped_type
207  ro<Factory, FP, ThrT, Stats>::operator[](const key_type &id) {
208  const typename colln_t::const_iterator i(internal_cache.find(id));
209  statistics_.accessed();
210  if (i!=internal_cache.end()) {
211  statistics_.hit();
212  return i->second;
213  } else {
214  typedef typename base_t::find_range_data find_range_type;
215 
216  const lock_t lock(serialize, lock_traits::infinite_timeout());
217  auto const &get_range_data=populate_pool<<typename thread_traits::populate_pool_t::joinable()<<find_range_type(base<Factory>::data_factory(), id);
218 
219  typedef typename base_t::flush_cache flush_cache_t;
220  flusher_pool<<flush_nonjoinable()<<flush_cache_t(*this);
221 
222  const std::pair<typename colln_t::const_iterator, bool> inserted_data(
223  internal_cache.insert(
224  typename colln_t::value_type(
225  id,
226  typename colln_t::value_type::second_type(get_range_data->data)
227  )
228  )
229  );
230  assert(inserted_data.second);
231  return inserted_data.first->second;
232  }
233  }
234 
235  template<class Factory, class FP, class ThrT, class Stats> inline void
236  ro<Factory, FP, ThrT, Stats>::flush(void) {
237  if (internal_cache.size()>high_water_mark) {
238  lock_t lock(serialize);
239  if (lock.try_lock()==lock_traits::atom_set) {
240  while (internal_cache.size()>low_water_mark) {
241  // Need to recalculate this in here, because the criterion may change...
242  const typename victimization_traits::criterion_t criterion(victimization_traits::select(internal_cache.begin(),internal_cache.end()));
243  const typename colln_t::iterator a_victim(std::find_if(internal_cache.begin(),internal_cache.end(),criterion));
244  assert(a_victim!=internal_cache.end());
245  internal_cache.erase(a_victim);
246  }
247  statistics_.flushed();
248  }
249  }
250  }
251 
252  template<class Factory, class FP, class ThrT, class Stats> inline const Stats &
253  ro<Factory, FP, ThrT, Stats>::statistics(void) const noexcept(true) {
254  return statistics_;
255  }
256 
257 } } }