OPeNDAP Hyrax Back End Server (BES)  Updated for version 3.8.3
BESCache3.cc
Go to the documentation of this file.
1 // BESCache3.cc
2 
3 // This file is part of bes, A C++ back-end server implementation framework
4 // for the OPeNDAP Data Access Protocol.
5 
6 // Copyright (c) 2012 OPeNDAP, Inc
7 // Author: James Gallagher <jgallagher@opendap.org>
8 // Patrick West <pwest@ucar.edu> and Jose Garcia <jgarcia@ucar.edu>
9 //
10 // This library is free software; you can redistribute it and/or
11 // modify it under the terms of the GNU Lesser General Public
12 // License as published by the Free Software Foundation; either
13 // version 2.1 of the License, or (at your option) any later version.
14 //
15 // This library is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 // Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public
21 // License along with this library; if not, write to the Free Software
22 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 //
24 // You can contact University Corporation for Atmospheric Research at
25 // 3080 Center Green Drive, Boulder, CO 80301
26 
27 #include "config.h"
28 
29 #include <sys/file.h>
30 #include <sys/stat.h>
31 #include <unistd.h>
32 #include <dirent.h>
33 #include <fcntl.h>
34 
35 #include <string>
36 #include <sstream>
37 #include <cstring>
38 #include <cerrno>
39 
40 #include "BESCache3.h"
41 
42 #include "BESSyntaxUserError.h"
43 #include "BESInternalError.h"
44 
45 #include "TheBESKeys.h"
46 #include "BESDebug.h"
47 #include "BESLog.h"
48 
49 using namespace std;
50 
51 // conversion factor
52 static const unsigned long long BYTES_PER_MEG = 1048576ULL;
53 
54 // Max cache size in megs, so we can check the user input and warn.
55 // 2^64 / 2^20 == 2^44
56 static const unsigned long long MAX_CACHE_SIZE_IN_MEGABYTES = (1ULL << 44);
57 
58 BESCache3 *BESCache3::d_instance = 0;
59 
60 // The BESCache3 code is a singleton that assumes it's running in the absence of threads but that
61 // the cache is shared by several processes, each of which have their own instance of BESCache3.
73 BESCache3 *
74 BESCache3::get_instance(BESKeys *keys, const string &cache_dir_key, const string &prefix_key, const string &size_key)
75 {
76  if (d_instance == 0)
77  d_instance = new BESCache3(keys, cache_dir_key, prefix_key, size_key);
78 
79  return d_instance;
80 }
81 
85 BESCache3 *
86 BESCache3::get_instance(const string &cache_dir, const string &prefix, unsigned long size)
87 {
88  if (d_instance == 0)
89  d_instance = new BESCache3(cache_dir, prefix, size);
90 
91  return d_instance;
92 }
93 
97 BESCache3 *
99 {
100  if (d_instance == 0)
101  throw BESInternalError("Tried to get the BESCache3 instance, but it hasn't been created yet", __FILE__, __LINE__);
102 
103  return d_instance;
104 }
105 
106 static inline string get_errno() {
107  char *s_err = strerror(errno);
108  if (s_err)
109  return s_err;
110  else
111  return "Unknown error.";
112 }
113 
114 // Apply cmd and type to the entire file.
115 // cmd is one of F_GETLK, F_SETLK, F_SETLKW, F_UNLCK
116 // type is one of F_RDLCK, F_WRLCK
117 static inline struct flock *lock(int type) {
118  static struct flock lock;
119  lock.l_type = type;
120  lock.l_whence = SEEK_SET;
121  lock.l_start = 0;
122  lock.l_len = 0;
123  lock.l_pid = getpid();
124 
125  return &lock;
126 }
127 
128 inline void BESCache3::m_record_descriptor(const string &file, int fd) {
129  BESDEBUG("cache", "BES Cache: recording descriptor: " << file << ", " << fd << endl);
130  d_locks.insert(std::pair<string, int>(file, fd));
131 }
132 
133 // Modified on 5/6/14 to support several open descriptors for a single file
134 // name. jhrg
135 inline int BESCache3::m_get_descriptor(const string &file) {
136  FilesAndLockDescriptors::iterator i = d_locks.find(file);
137  if (i == d_locks.end())
138  return -1;
139 
140  int fd = i->second;
141  BESDEBUG("cache", "BES Cache: getting descriptor: " << file << ", " << fd << endl);
142  d_locks.erase(i);
143  return fd;
144 }
145 
151 static void unlock(int fd)
152 {
153  if (fcntl(fd, F_SETLK, lock(F_UNLCK)) == -1) {
154  throw BESInternalError("An error occurred trying to unlock the file" + get_errno(), __FILE__, __LINE__);
155  }
156 
157  if (close(fd) == -1)
158  throw BESInternalError("Could not close the (just) unlocked file.", __FILE__, __LINE__);
159 }
160 
173 static bool getSharedLock(const string &file_name, int &ref_fd)
174 {
175  BESDEBUG("cache_internal", "getSharedLock: " << file_name <<endl);
176 
177  int fd;
178  if ((fd = open(file_name.c_str(), O_RDONLY)) < 0) {
179  switch (errno) {
180  case ENOENT:
181  return false;
182 
183  default:
184  throw BESInternalError("Could not get shared lock for " + file_name + ": " + get_errno(), __FILE__, __LINE__);
185  }
186  }
187 
188  struct flock *l = lock(F_RDLCK);
189  if (fcntl(fd, F_SETLKW, l) == -1) {
190  close(fd);
191  ostringstream oss;
192  oss << "cache process: " << l->l_pid << " triggered a locking error: " << get_errno();
193  throw BESInternalError(oss.str(), __FILE__, __LINE__);
194  }
195 
196  BESDEBUG("cache_internal", "getSharedLock exit: " << file_name <<endl);
197 
198  // Success
199  ref_fd = fd;
200  return true;
201 }
202 
203 #if 0
204 
216 static bool getExclusiveLock(string file_name, int &ref_fd)
217 {
218  BESDEBUG("cache_internal", "getExclusiveLock: " << file_name <<endl);
219 
220  int fd;
221  if ((fd = open(file_name.c_str(), O_RDWR)) < 0) {
222  switch (errno) {
223  case ENOENT:
224  return false;
225 
226  default:
227  throw BESInternalError("Could not get exclusive lock for " + file_name + ": " + get_errno(), __FILE__, __LINE__);
228  }
229  }
230 
231  struct flock *l = lock(F_WRLCK);
232  if (fcntl(fd, F_SETLKW, l) == -1) {
233  close(fd);
234  ostringstream oss;
235  oss << "cache process: " << l->l_pid << " triggered a locking error: " << get_errno();
236  throw BESInternalError(oss.str(), __FILE__, __LINE__);
237  }
238 
239  BESDEBUG("cache_internal", "getExclusiveLock exit: " << file_name <<endl);
240 
241  // Success
242  ref_fd = fd;
243  return true;
244 }
245 #endif
246 
258 static bool getExclusiveLockNB(string file_name, int &ref_fd)
259 {
260  BESDEBUG("cache_internal", "getExclusiveLock_nonblocking: " << file_name <<endl);
261 
262  int fd;
263  if ((fd = open(file_name.c_str(), O_RDWR)) < 0) {
264  switch (errno) {
265  case ENOENT:
266  return false;
267 
268  default:
269  throw BESInternalError("Could not get a non-blocking exclusive lock for " + file_name + ": " + get_errno(), __FILE__, __LINE__);
270  }
271  }
272 
273  struct flock *l = lock(F_WRLCK);
274  if (fcntl(fd, F_SETLK, l) == -1) {
275  switch (errno) {
276  case EAGAIN:
277  BESDEBUG("cache_internal", "getExclusiveLock_nonblocking exit (false): " << file_name << " by: " << l->l_pid << endl);
278  close(fd);
279  return false;
280 
281  default: {
282  close(fd);
283  ostringstream oss;
284  oss << "cache process: " << l->l_pid << " triggered a locking error: " << get_errno();
285  throw BESInternalError(oss.str(), __FILE__, __LINE__);
286  }
287  }
288  }
289 
290  BESDEBUG("cache_internal", "getExclusiveLock_nonblocking exit (true): " << file_name <<endl);
291 
292  // Success
293  ref_fd = fd;
294  return true;
295 }
296 
310 static bool createLockedFile(string file_name, int &ref_fd)
311 {
312  BESDEBUG("cache_internal", "createLockedFile: " << file_name <<endl);
313 
314  int fd;
315  if ((fd = open(file_name.c_str(), O_CREAT | O_EXCL | O_RDWR, 0666)) < 0) {
316  switch (errno) {
317  case EEXIST:
318  return false;
319 
320  default:
321  throw BESInternalError("Could not create locked file (" + file_name + "): " + get_errno(), __FILE__, __LINE__);
322  }
323  }
324 
325  struct flock *l = lock(F_WRLCK);
326  if (fcntl(fd, F_SETLKW, l) == -1) {
327  close(fd);
328  ostringstream oss;
329  oss << "cache process: " << l->l_pid << " triggered a locking error: " << get_errno();
330  throw BESInternalError(oss.str(), __FILE__, __LINE__);
331  }
332 
333  BESDEBUG("cache_internal", "createLockedFile exit: " << file_name <<endl);
334 
335  // Success
336  ref_fd = fd;
337  return true;
338 }
339 
341 void BESCache3::m_check_ctor_params()
342 {
343  if (d_cache_dir.empty()) {
344  string err = "The cache directory was not specified, must be non-empty";
345  throw BESSyntaxUserError(err, __FILE__, __LINE__);
346  }
347 
348  struct stat buf;
349  int statret = stat(d_cache_dir.c_str(), &buf);
350  if (statret != 0 || !S_ISDIR(buf.st_mode)) {
351  string err = "The cache directory " + d_cache_dir + " does not exist";
352  throw BESSyntaxUserError(err, __FILE__, __LINE__);
353  }
354 
355  if (d_prefix.empty()) {
356  string err = "The cache file prefix was not specified, must not be empty";
357  throw BESSyntaxUserError(err, __FILE__, __LINE__);
358  }
359 
360  if (d_max_cache_size_in_bytes <= 0) {
361  string err = "The cache size was not specified, must be greater than zero";
362  throw BESSyntaxUserError(err, __FILE__, __LINE__);
363  }
364 
365  // If the user specifies a cache that is too large,
366  // it is a user exception and we should tell them.
367  if (d_max_cache_size_in_bytes > MAX_CACHE_SIZE_IN_MEGABYTES) {
368  std::ostringstream msg;
369  msg << "The specified cache size was larger than the max cache size of: " << MAX_CACHE_SIZE_IN_MEGABYTES;
370  throw BESSyntaxUserError(msg.str(), __FILE__, __LINE__);
371  }
372 
373  BESDEBUG( "cache_internal", "BES Cache: directory " << d_cache_dir
374  << ", prefix " << d_prefix
375  << ", max size " << d_max_cache_size_in_bytes << endl );
376 }
377 
379 void BESCache3::m_initialize_cache_info()
380 {
381  d_max_cache_size_in_bytes = min(d_max_cache_size_in_bytes, MAX_CACHE_SIZE_IN_MEGABYTES);
382  if (d_max_cache_size_in_bytes > MAX_CACHE_SIZE_IN_MEGABYTES)
383  *(BESLog::TheLog()) << "Cache size too big in configuration file, set to max limit." << endl ;
384 
385  d_max_cache_size_in_bytes *= BYTES_PER_MEG;
386  d_target_size = d_max_cache_size_in_bytes * 0.8;
387 
388  m_check_ctor_params(); // Throws BESSyntaxUserError on error.
389 
390  d_cache_info = d_cache_dir + "/bes.cache.info";
391 
392  // See if we can create it. If so, that means it doesn't exist. So make it and
393  // set the cache initial size to zero.
394  if (createLockedFile(d_cache_info, d_cache_info_fd)) {
395  // initialize the cache size to zero
396  unsigned long long size = 0;
397  if (write(d_cache_info_fd, &size, sizeof(unsigned long long)) != sizeof(unsigned long long))
398  throw BESInternalError("Could not write size info to the cache info file in startup!", __FILE__, __LINE__);
399 
400  // This leaves the d_cache_info_fd file descriptor open
401  unlock_cache();
402  }
403  else {
404  if ((d_cache_info_fd = open(d_cache_info.c_str(), O_RDWR)) == -1) {
405  throw BESInternalError("Could not open the cache info file (" + d_cache_info + "): " + get_errno(), __FILE__, __LINE__);
406  }
407  }
408 
409  BESDEBUG("cache_internal", "d_cache_info_fd: " << d_cache_info_fd << endl);
410 }
411 
426 BESCache3::BESCache3(BESKeys *keys, const string &cache_dir_key, const string &prefix_key, const string &size_key) :
427  d_max_cache_size_in_bytes(0)
428 {
429  bool found = false;
430  keys->get_value(cache_dir_key, d_cache_dir, found);
431  if (!found)
432  throw BESSyntaxUserError("The cache directory key " + cache_dir_key + " was not found in the BES configuration file", __FILE__, __LINE__);
433 
434  found = false;
435  keys->get_value(prefix_key, d_prefix, found);
436  if (!found)
437  throw BESSyntaxUserError("The prefix key " + prefix_key + " was not found in the BES configuration file", __FILE__, __LINE__);
438 
439  found = false;
440  string cache_size_str;
441  keys->get_value(size_key, cache_size_str, found);
442  if (!found)
443  throw BESSyntaxUserError("The size key " + size_key + " was not found in the BES configuration file", __FILE__, __LINE__);
444 
445  std::istringstream is(cache_size_str);
446  is >> d_max_cache_size_in_bytes;
447 
448  m_initialize_cache_info();
449 }
450 
457 BESCache3::BESCache3(const string &cache_dir, const string &prefix, unsigned long size) :
458  d_cache_dir(cache_dir), d_prefix(prefix), d_max_cache_size_in_bytes(size)
459 {
460  m_initialize_cache_info();
461 }
462 
472 string BESCache3::get_cache_file_name(const string &src)
473 {
474  string target = src;
475  if (target.at(0) == '/') {
476  target = src.substr(1, target.length() - 1);
477  }
478  string::size_type slash = 0;
479  while ((slash = target.find('/')) != string::npos) {
480  target.replace(slash, 1, 1, BESCache3::BES_CACHE_CHAR);
481  }
482  string::size_type last_dot = target.rfind('.');
483  if (last_dot != string::npos) {
484  target = target.substr(0, last_dot);
485  }
486 
487  return d_cache_dir + "/" + d_prefix + BESCache3::BES_CACHE_CHAR + target;
488 }
489 
507 bool BESCache3::get_read_lock(const string &target, int &fd)
508 {
509  lock_cache_read();
510 
511  bool status = getSharedLock(target, fd);
512 
513  BESDEBUG("cache_internal", "BES Cache: get_read_lock: " << target << "(" << status << ")" << endl);
514 
515  if (status)
516  m_record_descriptor(target, fd);
517 
518  unlock_cache();
519 
520  return status;
521 }
522 
535 bool BESCache3::create_and_lock(const string &target, int &fd)
536 {
538 
539  bool status = createLockedFile(target, fd);
540 
541  BESDEBUG("cache_internal", "BES Cache: create_and_lock: " << target << "(" << status << ")" << endl);
542 
543  if (status)
544  m_record_descriptor(target, fd);
545 
546  unlock_cache();
547 
548  return status;
549 
550 }
551 
566 {
567  struct flock lock;
568  lock.l_type = F_RDLCK;
569  lock.l_whence = SEEK_SET;
570  lock.l_start = 0;
571  lock.l_len = 0;
572  lock.l_pid = getpid();
573 
574  if (fcntl(fd, F_SETLKW, &lock) == -1) {
575  throw BESInternalError("Could not convert an exclusive to a shared lock: " + get_errno(), __FILE__, __LINE__);
576  }
577 }
578 
588 {
589  BESDEBUG("cache_internal", "lock_cache - d_cache_info_fd: " << d_cache_info_fd << endl);
590 
591  if (fcntl(d_cache_info_fd, F_SETLKW, lock(F_WRLCK)) == -1) {
592  throw BESInternalError("An error occurred trying to lock the cache-control file" + get_errno(), __FILE__, __LINE__);
593  }
594 }
595 
600 {
601  BESDEBUG("cache_internal", "lock_cache - d_cache_info_fd: " << d_cache_info_fd << endl);
602 
603  if (fcntl(d_cache_info_fd, F_SETLKW, lock(F_RDLCK)) == -1) {
604  throw BESInternalError("An error occurred trying to lock the cache-control file" + get_errno(), __FILE__, __LINE__);
605  }
606 }
607 
614 {
615  BESDEBUG("cache_internal", "BES Cache: unlock: cache_info (fd: " << d_cache_info_fd << ")" << endl);
616 
617  if (fcntl(d_cache_info_fd, F_SETLK, lock(F_UNLCK)) == -1) {
618  throw BESInternalError("An error occurred trying to unlock the cache-control file" + get_errno(), __FILE__, __LINE__);
619  }
620 }
621 
633 void BESCache3::unlock_and_close(const string &file_name)
634 {
635  BESDEBUG("cache_internal", "BES Cache: unlock file: " << file_name << endl);
636 
637  int fd = m_get_descriptor(file_name); // returns -1 when no more files desp. remain
638  while (fd != -1) {
639  unlock(fd);
640  fd = m_get_descriptor(file_name);
641  }
642 }
643 
650 {
651  BESDEBUG("cache_internal", "BES Cache: unlock fd: " << fd << endl);
652 
653  unlock(fd);
654 
655  BESDEBUG("cache_internal", "BES Cache: unlock " << fd << " Success" << endl);
656 }
657 
668 unsigned long long BESCache3::update_cache_info(const string &target)
669 {
670  try
671  {
673 
674  if (lseek(d_cache_info_fd, 0, SEEK_SET) == -1)
675  throw BESInternalError("Could not rewind to front of cache info file.", __FILE__, __LINE__);
676 
677  // read the size from the cache info file
678  unsigned long long current_size;
679  if (read(d_cache_info_fd, &current_size, sizeof(unsigned long long)) != sizeof(unsigned long long))
680  throw BESInternalError("Could not get read size info from the cache info file!", __FILE__, __LINE__);
681 
682  struct stat buf;
683  int statret = stat(target.c_str(), &buf);
684  if (statret == 0)
685  current_size += buf.st_size;
686  else
687  throw BESInternalError("Could not read the size of the new file: " + target + " : " + get_errno(), __FILE__, __LINE__);
688 
689  BESDEBUG("cache_internal", "BES Cache: cache size updated to: " << current_size << endl);
690 
691  if (lseek(d_cache_info_fd, 0, SEEK_SET) == -1)
692  throw BESInternalError("Could not rewind to front of cache info file.", __FILE__, __LINE__);
693 
694  if (write(d_cache_info_fd, &current_size, sizeof(unsigned long long)) != sizeof(unsigned long long))
695  throw BESInternalError("Could not write size info from the cache info file!", __FILE__, __LINE__);
696 
697  unlock_cache();
698  return current_size;
699  }
700  catch (...)
701  {
702  unlock_cache();
703  throw;
704  }
705 
706  return 0; // quite warnings
707 }
708 
713 bool BESCache3::cache_too_big(unsigned long long current_size) const
714 {
715  return current_size > d_max_cache_size_in_bytes;
716 }
717 
725 unsigned long long BESCache3::get_cache_size()
726 {
727  try
728  {
729  lock_cache_read();
730 
731  if (lseek(d_cache_info_fd, 0, SEEK_SET) == -1)
732  throw BESInternalError("Could not rewind to front of cache info file.", __FILE__, __LINE__);
733  // read the size from the cache info file
734  unsigned long long current_size;
735  if (read(d_cache_info_fd, &current_size, sizeof(unsigned long long)) != sizeof(unsigned long long))
736  throw BESInternalError("Could not get read size info from the cache info file!", __FILE__, __LINE__);
737 
738  unlock_cache();
739  return current_size;
740  }
741  catch (...)
742  {
743  unlock_cache();
744  throw;
745  }
746 
747  return 0; //quite warnings
748 }
749 
750 
751 static bool entry_op(cache_entry &e1, cache_entry &e2)
752 {
753  return e1.time < e2.time;
754 }
755 
757 unsigned long long BESCache3::m_collect_cache_dir_info(CacheFiles &contents)
758 {
759  DIR *dip = opendir(d_cache_dir.c_str());
760  if (!dip)
761  throw BESInternalError("Unable to open cache directory " + d_cache_dir, __FILE__, __LINE__);
762 
763  struct dirent *dit;
764  vector<string> files;
765  // go through the cache directory and collect all of the files that
766  // start with the matching prefix
767  while ((dit = readdir(dip)) != NULL) {
768  string dirEntry = dit->d_name;
769  if (dirEntry.compare(0, d_prefix.length(), d_prefix) == 0) {
770  files.push_back(d_cache_dir + "/" + dirEntry);
771  }
772  }
773 
774  closedir(dip);
775 
776  unsigned long long current_size = 0;
777  struct stat buf;
778  for (vector<string>::iterator file = files.begin(); file != files.end(); ++file) {
779  if (stat(file->c_str(), &buf) == 0) {
780  current_size += buf.st_size;
781  cache_entry entry;
782  entry.name = *file;
783  entry.size = buf.st_size;
784  entry.time = buf.st_atime;
785  // Sanity check; Removed after initial testing since some files might be zero bytes
786 #if 0
787  if (entry.size == 0)
788  throw BESInternalError("Zero-byte file found in cache. " + *file, __FILE__, __LINE__);
789 #endif
790  contents.push_back(entry);
791  }
792  }
793 
794  // Sort so smaller (older) times are first.
795  contents.sort(entry_op);
796 
797  return current_size;
798 }
799 
811 void BESCache3::update_and_purge(const string &new_file)
812 {
813  BESDEBUG("cache_purge", "purge - starting the purge" << endl);
814 
815  try {
817 
818  CacheFiles contents;
819  unsigned long long computed_size = m_collect_cache_dir_info(contents);
820 
821  if (BESISDEBUG( "cache_contents" )) {
822  BESDEBUG( "cache_contents", endl << "BEFORE Purge " << computed_size/BYTES_PER_MEG << endl );
823  CacheFiles::iterator ti = contents.begin();
824  CacheFiles::iterator te = contents.end();
825  for (; ti != te; ti++) {
826  BESDEBUG( "cache_contents", (*ti).time << ": " << (*ti).name << ": size " << (*ti).size/BYTES_PER_MEG << endl );
827  }
828  }
829 
830  BESDEBUG( "cache_purge", "purge - current and target size (in MB) " << computed_size/BYTES_PER_MEG << ", " << d_target_size/BYTES_PER_MEG << endl );
831 
832  // This deletes files and updates computed_size
833  if (cache_too_big(computed_size)) {
834 
835  // d_target_size is 80% of the maximum cache size.
836  // Grab the first which is the oldest in terms of access time.
837  CacheFiles::iterator i = contents.begin();
838  while (i != contents.end() && computed_size > d_target_size) {
839  // Grab an exclusive lock but do not block - if another process has the file locked
840  // just move on to the next file. Also test to see if the current file is the file
841  // this process just added to the cache - don't purge that!
842  int cfile_fd;
843  if (i->name != new_file && getExclusiveLockNB(i->name, cfile_fd)) {
844  BESDEBUG( "cache_purge", "purge: " << i->name << " removed." << endl );
845 
846  if (unlink(i->name.c_str()) != 0)
847  throw BESInternalError("Unable to purge the file " + i->name + " from the cache: " + get_errno(), __FILE__, __LINE__);
848 
849  unlock(cfile_fd);
850  computed_size -= i->size;
851  }
852 #if 1
853  else {
854  // This information is useful when debugging... Might comment out for production
855  BESDEBUG( "cache_purge", "purge: " << i->name << " is in use." << endl );
856  }
857 #endif
858  ++i;
859 
860  BESDEBUG( "cache_purge", "purge - current and target size (in MB) " << computed_size/BYTES_PER_MEG << ", " << d_target_size/BYTES_PER_MEG << endl );
861  }
862 
863  }
864 
865  if (lseek(d_cache_info_fd, 0, SEEK_SET) == -1)
866  throw BESInternalError("Could not rewind to front of cache info file.", __FILE__, __LINE__);
867 
868  if(write(d_cache_info_fd, &computed_size, sizeof(unsigned long long)) != sizeof(unsigned long long))
869  throw BESInternalError("Could not write size info to the cache info file!", __FILE__, __LINE__);
870 
871  if (BESISDEBUG( "cache_contents" )) {
872  contents.clear();
873  computed_size = m_collect_cache_dir_info(contents);
874  BESDEBUG( "cache_contents", endl << "AFTER Purge " << computed_size/BYTES_PER_MEG << endl );
875  CacheFiles::iterator ti = contents.begin();
876  CacheFiles::iterator te = contents.end();
877  for (; ti != te; ti++) {
878  BESDEBUG( "cache_contents", (*ti).time << ": " << (*ti).name << ": size " << (*ti).size/BYTES_PER_MEG << endl );
879  }
880  }
881 
882  unlock_cache();
883  }
884  catch(...) {
885  unlock_cache();
886  throw;
887  }
888 }
889 
897 void BESCache3::dump(ostream &strm) const
898 {
899  strm << BESIndent::LMarg << "BESCache3::dump - (" << (void *) this << ")" << endl;
901  strm << BESIndent::LMarg << "cache dir: " << d_cache_dir << endl;
902  strm << BESIndent::LMarg << "prefix: " << d_prefix << endl;
903  strm << BESIndent::LMarg << "size (bytes): " << d_max_cache_size_in_bytes << endl;
905 }
906 
virtual void exclusive_to_shared_lock(int fd)
Transfer from an exclusive lock to a shared lock.
Definition: BESCache3.cc:565
virtual void dump(ostream &strm) const
dumps information about this object
Definition: BESCache3.cc:897
#define BESISDEBUG(x)
macro used to determine if the specified debug context is set
Definition: BESDebug.h:83
std::list< cache_entry > CacheFiles
Definition: BESCache3.h:46
exception thrown if inernal error encountered
time_t time
Definition: BESCache3.h:43
virtual bool cache_too_big(unsigned long long current_size) const
look at the cache size; is it too large? Look at the cache size and see if it is too big...
Definition: BESCache3.cc:713
Definition: BESCache3.h:40
virtual void lock_cache_write()
Get an exclusive lock on the 'cache info' file.
Definition: BESCache3.cc:587
unsigned long long size
Definition: BESCache3.h:42
string name
Definition: BESCache3.h:41
virtual void unlock_and_close(const string &target)
Unlock the named file.
Definition: BESCache3.cc:633
static void Indent()
Definition: BESIndent.cc:38
error thrown if there is a user syntax error in the request or any other user error ...
virtual void lock_cache_read()
Get a shared lock on the 'cache info' file.
Definition: BESCache3.cc:599
mapping of key/value pairs defining different behaviors of an application.
Definition: BESKeys.h:84
Implementation of a caching mechanism for compressed data.
Definition: BESCache3.h:71
static ostream & LMarg(ostream &strm)
Definition: BESIndent.cc:73
virtual unsigned long long update_cache_info(const string &target)
Update the cache info file to include 'target'.
Definition: BESCache3.cc:668
virtual bool create_and_lock(const string &target, int &fd)
Create a file in the cache and lock it for write access.
Definition: BESCache3.cc:535
void get_value(const string &s, string &val, bool &found)
Retrieve the value of a given key, if set.
Definition: BESKeys.cc:453
virtual bool get_read_lock(const string &target, int &fd)
Get a read-only lock on the file if it exists.
Definition: BESCache3.cc:507
static BESLog * TheLog()
Definition: BESLog.cc:347
string get_cache_file_name(const string &src)
Build the name of file that will holds the uncompressed data from 'src' in the cache.
Definition: BESCache3.cc:472
virtual void update_and_purge(const string &new_file)
Purge files from the cache.
Definition: BESCache3.cc:811
virtual void unlock_cache()
Unlock the cache info file.
Definition: BESCache3.cc:613
#define BESDEBUG(x, y)
macro used to send debug information to the debug stream
Definition: BESDebug.h:64
static void UnIndent()
Definition: BESIndent.cc:44
virtual unsigned long long get_cache_size()
Get the cache size.
Definition: BESCache3.cc:725
static BESCache3 * get_instance()
Get an instance of the BESCache3 object.
Definition: BESCache3.cc:98