OPeNDAP Hyrax Back End Server (BES)  Updated for version 3.8.3
BESFileLockingCache.cc
Go to the documentation of this file.
1 // BESFileLockingCache.cc
2 
3 // This file was originally part of bes, A C++ back-end server
4 // implementation framework for the OPeNDAP Data Access Protocol.
5 // Copied to libdap. This is used to cache responses built from
6 // functional CE expressions.
7 
8 // Moved back to the BES. 6/11/13 jhrg
9 
10 // Copyright (c) 2012 OPeNDAP, Inc
11 // Author: James Gallagher <jgallagher@opendap.org>
12 // Patrick West <pwest@ucar.edu> and Jose Garcia <jgarcia@ucar.edu>
13 //
14 // This library is free software; you can redistribute it and/or
15 // modify it under the terms of the GNU Lesser General Public
16 // License as published by the Free Software Foundation; either
17 // version 2.1 of the License, or (at your option) any later version.
18 //
19 // This library is distributed in the hope that it will be useful,
20 // but WITHOUT ANY WARRANTY; without even the implied warranty of
21 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 // Lesser General Public License for more details.
23 //
24 // You should have received a copy of the GNU Lesser General Public
25 // License along with this library; if not, write to the Free Software
26 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27 //
28 // You can contact University Corporation for Atmospheric Research at
29 // 3080 Center Green Drive, Boulder, CO 80301
30 
31 #include "config.h"
32 
33 #include <sys/file.h>
34 #include <sys/stat.h>
35 #include <unistd.h>
36 #include <dirent.h>
37 #include <fcntl.h>
38 
39 #ifdef HAVE_STDLIB_H
40 #include <stdlib.h>
41 #endif
42 
43 #include <string>
44 #include <sstream>
45 #include <vector>
46 #include <cstring>
47 #include <cerrno>
48 
49 //#define DODS_DEBUG
50 
51 #include "BESInternalError.h"
52 
53 #include "BESDebug.h"
54 #include "BESLog.h"
55 
56 #include "BESFileLockingCache.h"
57 
58 using namespace std;
59 
60 // conversion factor
61 static const unsigned long long BYTES_PER_MEG = 1048576ULL;
62 
63 // Max cache size in megs, so we can check the user input and warn.
64 // 2^64 / 2^20 == 2^44
65 static const unsigned long long MAX_CACHE_SIZE_IN_MEGABYTES = (1ULL << 44);
66 
80 BESFileLockingCache::BESFileLockingCache(const string &cache_dir, const string &prefix, unsigned long long size) :
81  d_cache_dir(cache_dir), d_prefix(prefix), d_max_cache_size_in_bytes(size)
82 {
83  m_initialize_cache_info();
84 }
85 
86 void BESFileLockingCache::initialize(const string &cache_dir, const string &prefix, unsigned long long size)
87 {
88  d_cache_dir = cache_dir;
89  d_prefix = prefix;
90  d_max_cache_size_in_bytes = size;
91 
92  m_initialize_cache_info();
93 }
94 
95 static inline string get_errno() {
96  char *s_err = strerror(errno);
97  if (s_err)
98  return s_err;
99  else
100  return "Unknown error.";
101 }
102 
103 // Build a lock of a certain type.
104 static inline struct flock *lock(int type) {
105  static struct flock lock;
106  lock.l_type = type;
107  lock.l_whence = SEEK_SET;
108  lock.l_start = 0;
109  lock.l_len = 0;
110  lock.l_pid = getpid();
111 
112  return &lock;
113 }
114 
115 inline void BESFileLockingCache::m_record_descriptor(const string &file, int fd) {
116  BESDEBUG("cache", "DAP Cache: recording descriptor: " << file << ", " << fd << endl);
117  d_locks.insert(std::pair<string, int>(file, fd));
118 }
119 
120 inline int BESFileLockingCache::m_get_descriptor(const string &file) {
121  BESDEBUG("cache", "BESFileLockingCache::m_get_descriptor; d_locks size: " << d_locks.size() << endl);
122  FilesAndLockDescriptors::iterator i = d_locks.find(file);
123  if (i == d_locks.end())
124  return -1;
125 
126  int fd = i->second;
127  BESDEBUG("cache", "DAP Cache: getting descriptor: " << file << ", " << fd << endl);
128  d_locks.erase(i);
129  return fd;
130 }
131 
137 static void unlock(int fd)
138 {
139  if (fcntl(fd, F_SETLK, lock(F_UNLCK)) == -1) {
140  throw BESInternalError( "An error occurred trying to unlock the file: " + get_errno(), __FILE__, __LINE__);
141  }
142 
143  if (close(fd) == -1)
144  throw BESInternalError("Could not close the (just) unlocked file.", __FILE__, __LINE__);
145 }
146 
159 static bool getSharedLock(const string &file_name, int &ref_fd)
160 {
161  BESDEBUG("cache", "getSharedLock: " << file_name <<endl);
162 
163  int fd;
164  if ((fd = open(file_name.c_str(), O_RDONLY)) < 0) {
165  switch (errno) {
166  case ENOENT:
167  return false;
168 
169  default:
170  throw BESInternalError( get_errno(), __FILE__, __LINE__);
171  }
172  }
173 
174  struct flock *l = lock(F_RDLCK);
175  if (fcntl(fd, F_SETLKW, l) == -1) {
176  close(fd);
177  ostringstream oss;
178  oss << "cache process: " << l->l_pid << " triggered a locking error: " << get_errno();
179  throw BESInternalError( oss.str(), __FILE__, __LINE__);
180  }
181 
182  BESDEBUG("cache", "getSharedLock exit: " << file_name <<endl);
183 
184  // Success
185  ref_fd = fd;
186  return true;
187 }
188 
201 bool BESFileLockingCache::getExclusiveLock(string file_name, int &ref_fd)
202 {
203  BESDEBUG("cache", "BESFileLockingCache::getExclusiveLock() - " << file_name <<endl);
204 
205  int fd;
206  if ((fd = open(file_name.c_str(), O_RDWR)) < 0) {
207  switch (errno) {
208  case ENOENT:
209  return false;
210 
211  default:
212  throw BESInternalError(get_errno(), __FILE__, __LINE__);
213  }
214  }
215 
216  struct flock *l = lock(F_WRLCK);
217  if (fcntl(fd, F_SETLKW, l) == -1) {
218  close(fd);
219  ostringstream oss;
220  oss << "cache process: " << l->l_pid << " triggered a locking error: " << get_errno();
221  throw BESInternalError(oss.str(), __FILE__, __LINE__);
222  }
223 
224  BESDEBUG("cache", "BESFileLockingCache::getExclusiveLock() - exit: " << file_name <<endl);
225 
226  // Success
227  ref_fd = fd;
228  return true;
229 }
230 
242 static bool getExclusiveLockNB(string file_name, int &ref_fd)
243 {
244  BESDEBUG("cache", "getExclusiveLock_nonblocking: " << file_name <<endl);
245 
246  int fd;
247  if ((fd = open(file_name.c_str(), O_RDWR)) < 0) {
248  switch (errno) {
249  case ENOENT:
250  return false;
251 
252  default:
253  throw BESInternalError(get_errno(), __FILE__, __LINE__);
254  }
255  }
256 
257  struct flock *l = lock(F_WRLCK);
258  if (fcntl(fd, F_SETLK, l) == -1) {
259  switch (errno) {
260  case EAGAIN:
261  BESDEBUG("cache", "getExclusiveLock_nonblocking exit (false): " << file_name << " by: " << l->l_pid << endl);
262  close(fd);
263  return false;
264 
265  default: {
266  close(fd);
267  ostringstream oss;
268  oss << "cache process: " << l->l_pid << " triggered a locking error: " << get_errno();
269  throw BESInternalError(oss.str(), __FILE__, __LINE__);
270  }
271  }
272  }
273 
274  BESDEBUG("cache", "getExclusiveLock_nonblocking exit (true): " << file_name <<endl);
275 
276  // Success
277  ref_fd = fd;
278  return true;
279 }
280 
294 static bool createLockedFile(string file_name, int &ref_fd)
295 {
296  BESDEBUG("cache", "createLockedFile: " << file_name <<endl);
297 
298  int fd;
299  if ((fd = open(file_name.c_str(), O_CREAT | O_EXCL | O_RDWR, 0666)) < 0) {
300  switch (errno) {
301  case EEXIST:
302  return false;
303 
304  default:
305  throw BESInternalError(get_errno(), __FILE__, __LINE__);
306  }
307  }
308 
309  struct flock *l = lock(F_WRLCK);
310  if (fcntl(fd, F_SETLKW, l) == -1) {
311  close(fd);
312  ostringstream oss;
313  oss << "cache process: " << l->l_pid << " triggered a locking error: " << get_errno();
314  throw BESInternalError(oss.str(), __FILE__, __LINE__);
315  }
316 
317  BESDEBUG("cache", "createLockedFile exit: " << file_name <<endl);
318 
319  // Success
320  ref_fd = fd;
321  return true;
322 }
323 
325 void BESFileLockingCache::m_check_ctor_params()
326 {
327  if (d_cache_dir.empty()) {
328  string err = "The cache directory was not specified";
329  throw BESInternalError(err, __FILE__, __LINE__);
330  }
331 
332  struct stat buf;
333  int statret = stat(d_cache_dir.c_str(), &buf);
334  if (statret != 0 || !S_ISDIR(buf.st_mode)) {
335  // Try to make the directory
336  int status = mkdir(d_cache_dir.c_str(), 0775);
337  if (status != 0) {
338  string err = "The cache directory " + d_cache_dir + " does not exist or could not be created.";
339  throw BESInternalError(err, __FILE__, __LINE__);
340  }
341  }
342 
343  if (d_prefix.empty()) {
344  string err = "The cache file prefix was not specified, must not be empty";
345  throw BESInternalError(err, __FILE__, __LINE__);
346  }
347 
348  if (d_max_cache_size_in_bytes <= 0) {
349  string err = "The cache size was not specified, must be greater than zero";
350  throw BESInternalError(err, __FILE__, __LINE__);
351  }
352 
353  BESDEBUG("cache", "DAP Cache: directory " << d_cache_dir << ", prefix " << d_prefix
354  << ", max size " << d_max_cache_size_in_bytes << endl );
355 }
356 
358 void BESFileLockingCache::m_initialize_cache_info()
359 {
360  // The value set in configuration files, etc., is the size in megabytes. The private
361  // variable holds the size in bytes (converted below).
362  d_max_cache_size_in_bytes = min(d_max_cache_size_in_bytes, MAX_CACHE_SIZE_IN_MEGABYTES);
363  d_max_cache_size_in_bytes *= BYTES_PER_MEG;
364  d_target_size = d_max_cache_size_in_bytes * 0.8;
365 
366  m_check_ctor_params(); // Throws BESInternalError on error.
367 
368  d_cache_info = d_cache_dir + "/dap.cache.info";
369 
370  // See if we can create it. If so, that means it doesn't exist. So make it and
371  // set the cache initial size to zero.
372  if (createLockedFile(d_cache_info, d_cache_info_fd)) {
373  // initialize the cache size to zero
374  unsigned long long size = 0;
375  if (write(d_cache_info_fd, &size, sizeof(unsigned long long)) != sizeof(unsigned long long))
376  throw BESInternalError("Could not write size info to the cache info file `"+d_cache_info+"`", __FILE__, __LINE__);
377 
378  // This leaves the d_cache_info_fd file descriptor open
379  unlock_cache();
380  }
381  else {
382  if ((d_cache_info_fd = open(d_cache_info.c_str(), O_RDWR)) == -1) {
383  throw BESInternalError(get_errno(), __FILE__, __LINE__);
384  }
385  }
386 
387  // cerr << endl << "***** BESFileLockingCache::m_initialize_cache_info() completed. d_cache_info_fd: " << d_cache_info_fd << endl;
388 
389  BESDEBUG("cache", "d_cache_info_fd: " << d_cache_info_fd << endl);
390 }
391 
407 string BESFileLockingCache::get_cache_file_name(const string &src, bool mangle)
408 {
409  string target = src;
410 
411  if (mangle) {
412  if (target.at(0) == '/') {
413  target = src.substr(1, target.length() - 1);
414  }
415  string::size_type slash = 0;
416  while ((slash = target.find('/')) != string::npos) {
417  target.replace(slash, 1, 1, BESFileLockingCache::DAP_CACHE_CHAR);
418  }
419  string::size_type last_dot = target.rfind('.');
420  if (last_dot != string::npos) {
421  target = target.substr(0, last_dot);
422  }
423  }
424  BESDEBUG("cache", " d_cache_dir: '" << d_cache_dir << "'" << endl);
425  BESDEBUG("cache", " d_prefix: '" << d_prefix << "'" << endl);
426  BESDEBUG("cache", " target: '" << target << "'" << endl);
427 
428  return d_cache_dir + "/" + d_prefix + BESFileLockingCache::DAP_CACHE_CHAR + target;
429 }
430 
448 bool BESFileLockingCache::get_read_lock(const string &target, int &fd)
449 {
450  lock_cache_read();
451 
452  bool status = getSharedLock(target, fd);
453 
454  BESDEBUG("cache", "BESFileLockingCache: get_read_lock: " << target << " (status: " << status << ", fd: " << fd << ")" << endl);
455 
456  if (status)
457  m_record_descriptor(target, fd);
458 
459  unlock_cache();
460 
461  return status;
462 }
463 
476 bool BESFileLockingCache::create_and_lock(const string &target, int &fd)
477 {
479 
480  bool status = createLockedFile(target, fd);
481 
482  BESDEBUG("cache", "BESFileLockingCache: create_and_lock: " << target << " (status: " << status << ", fd: " << fd << ")" << endl);
483 
484  if (status)
485  m_record_descriptor(target, fd);
486 
487  unlock_cache();
488 
489  return status;
490 
491 }
492 
507 {
508  struct flock lock;
509  lock.l_type = F_RDLCK;
510  lock.l_whence = SEEK_SET;
511  lock.l_start = 0;
512  lock.l_len = 0;
513  lock.l_pid = getpid();
514 
515  if (fcntl(fd, F_SETLKW, &lock) == -1) {
516  throw BESInternalError(get_errno(), __FILE__, __LINE__);
517  }
518 }
519 
529 {
530  BESDEBUG("cache", "lock_cache - d_cache_info_fd: " << d_cache_info_fd << endl);
531 
532  if (fcntl(d_cache_info_fd, F_SETLKW, lock(F_WRLCK)) == -1) {
533  throw BESInternalError("An error occurred trying to lock the cache-control file" + get_errno(), __FILE__, __LINE__);
534  }
535 }
536 
541 {
542  BESDEBUG("cache", "lock_cache - d_cache_info_fd: " << d_cache_info_fd << endl);
543 
544  if (fcntl(d_cache_info_fd, F_SETLKW, lock(F_RDLCK)) == -1) {
545  throw BESInternalError("An error occurred trying to lock the cache-control file" + get_errno(), __FILE__, __LINE__);
546  }
547 }
548 
555 {
556  BESDEBUG("cache", "DAP Cache: unlock: cache_info (fd: " << d_cache_info_fd << ")" << endl);
557 
558  if (fcntl(d_cache_info_fd, F_SETLK, lock(F_UNLCK)) == -1) {
559  throw BESInternalError("An error occurred trying to unlock the cache-control file" + get_errno(), __FILE__, __LINE__);
560  }
561 }
562 
578 void BESFileLockingCache::unlock_and_close(const string &file_name)
579 {
580  BESDEBUG("cache", "DAP Cache: unlock file: " << file_name << endl);
581 
582  int fd = m_get_descriptor(file_name); // returns -1 when no more files desp. remain
583  while (fd != -1) {
584  unlock(fd);
585  fd = m_get_descriptor(file_name);
586  }
587 }
588 
589 #if 0
590 // I removed this because it will unlock() the file descriptor without
591 // removing it from the list of registered fds. This can lead to errors
592 // when the other version is called because a given descriptor appears
593 // more than once in the list of descriptors or a fd in the list is no
594 // longer open. jhrg 8/13/14
595 
602 {
603  BESDEBUG("cache", "DAP Cache: unlock fd: " << fd << endl);
604 
605  unlock(fd);
606 
607  BESDEBUG("cache", "DAP Cache: unlock " << fd << " Success" << endl);
608 }
609 #endif
610 
621 unsigned long long BESFileLockingCache::update_cache_info(const string &target)
622 {
623  unsigned long long current_size;
624  try {
626 
627  if (lseek(d_cache_info_fd, 0, SEEK_SET) == -1)
628  throw BESInternalError("Could not rewind to front of cache info file.", __FILE__, __LINE__);
629 
630  // read the size from the cache info file
631  if (read(d_cache_info_fd, &current_size, sizeof(unsigned long long)) != sizeof(unsigned long long))
632  throw BESInternalError("Could not get read size info from the cache info file!", __FILE__, __LINE__);
633 
634  struct stat buf;
635  int statret = stat(target.c_str(), &buf);
636  if (statret == 0)
637  current_size += buf.st_size;
638  else
639  throw BESInternalError("Could not read the size of the new file: " + target + " : " + get_errno(), __FILE__, __LINE__);
640 
641  BESDEBUG("cache", "DAP Cache: cache size updated to: " << current_size << endl);
642 
643  if (lseek(d_cache_info_fd, 0, SEEK_SET) == -1)
644  throw BESInternalError("Could not rewind to front of cache info file.", __FILE__, __LINE__);
645 
646  if(write(d_cache_info_fd, &current_size, sizeof(unsigned long long)) != sizeof(unsigned long long))
647  throw BESInternalError("Could not write size info from the cache info file!", __FILE__, __LINE__);
648 
649  unlock_cache();
650  }
651  catch (...) {
652  unlock_cache();
653  throw;
654  }
655 
656  return current_size;
657 }
658 
663 bool BESFileLockingCache::cache_too_big(unsigned long long current_size) const
664 {
665  return current_size > d_max_cache_size_in_bytes;
666 }
667 
676 {
677  unsigned long long current_size;
678  try {
679  lock_cache_read();
680 
681  if (lseek(d_cache_info_fd, 0, SEEK_SET) == -1)
682  throw BESInternalError("Could not rewind to front of cache info file.", __FILE__, __LINE__);
683  // read the size from the cache info file
684  if(read(d_cache_info_fd, &current_size, sizeof(unsigned long long)) != sizeof(unsigned long long))
685  throw BESInternalError("Could not get read size info from the cache info file!", __FILE__, __LINE__);
686 
687  unlock_cache();
688  }
689  catch(...) {
690  unlock_cache();
691  throw;
692  }
693 
694  return current_size;
695 }
696 
697 
698 static bool entry_op(cache_entry &e1, cache_entry &e2)
699 {
700  return e1.time < e2.time;
701 }
702 
704 unsigned long long BESFileLockingCache::m_collect_cache_dir_info(CacheFiles &contents)
705 {
706  DIR *dip = opendir(d_cache_dir.c_str());
707  if (!dip)
708  throw BESInternalError("Unable to open cache directory " + d_cache_dir, __FILE__, __LINE__);
709 
710  struct dirent *dit;
711  vector<string> files;
712  // go through the cache directory and collect all of the files that
713  // start with the matching prefix
714  while ((dit = readdir(dip)) != NULL) {
715  string dirEntry = dit->d_name;
716  if (dirEntry.compare(0, d_prefix.length(), d_prefix) == 0) {
717  files.push_back(d_cache_dir + "/" + dirEntry);
718  }
719  }
720 
721  closedir(dip);
722 
723  unsigned long long current_size = 0;
724  struct stat buf;
725  for (vector<string>::iterator file = files.begin(); file != files.end(); ++file) {
726  if (stat(file->c_str(), &buf) == 0) {
727  current_size += buf.st_size;
728  cache_entry entry;
729  entry.name = *file;
730  entry.size = buf.st_size;
731  entry.time = buf.st_atime;
732  // Sanity check; Removed after initial testing since some files might be zero bytes
733 #if 0
734  if (entry.size == 0)
735  throw BESInternalError("Zero-byte file found in cache. " + *file, __FILE__, __LINE__);
736 #endif
737  contents.push_back(entry);
738  }
739  }
740 
741  // Sort so smaller (older) times are first.
742  contents.sort(entry_op);
743 
744  return current_size;
745 }
746 
758 void BESFileLockingCache::update_and_purge(const string &new_file)
759 {
760  BESDEBUG("cache", "purge - starting the purge" << endl);
761 
762  try {
764 
765  CacheFiles contents;
766  unsigned long long computed_size = m_collect_cache_dir_info(contents);
767 #if 0
768  if (BESISDEBUG( "cache_contents" )) {
769  BESDEBUG("cache", "BEFORE Purge " << computed_size/BYTES_PER_MEG << endl );
770  CacheFiles::iterator ti = contents.begin();
771  CacheFiles::iterator te = contents.end();
772  for (; ti != te; ti++) {
773  BESDEBUG("cache", (*ti).time << ": " << (*ti).name << ": size " << (*ti).size/BYTES_PER_MEG << endl );
774  }
775  }
776 #endif
777  BESDEBUG("cache", "purge - current and target size (in MB) " << computed_size/BYTES_PER_MEG << ", " << d_target_size/BYTES_PER_MEG << endl );
778 
779  // This deletes files and updates computed_size
780  if (cache_too_big(computed_size)) {
781 
782  // d_target_size is 80% of the maximum cache size.
783  // Grab the first which is the oldest in terms of access time.
784  CacheFiles::iterator i = contents.begin();
785  while (i != contents.end() && computed_size > d_target_size) {
786  // Grab an exclusive lock but do not block - if another process has the file locked
787  // just move on to the next file. Also test to see if the current file is the file
788  // this process just added to the cache - don't purge that!
789  int cfile_fd;
790  if (i->name != new_file && getExclusiveLockNB(i->name, cfile_fd)) {
791  BESDEBUG("cache", "purge: " << i->name << " removed." << endl );
792 
793  if (unlink(i->name.c_str()) != 0)
794  throw BESInternalError("Unable to purge the file " + i->name + " from the cache: " + get_errno(), __FILE__, __LINE__);
795 
796  unlock(cfile_fd);
797  computed_size -= i->size;
798  }
799  ++i;
800 
801  BESDEBUG("cache", "purge - current and target size (in MB) " << computed_size/BYTES_PER_MEG << ", " << d_target_size/BYTES_PER_MEG << endl );
802  }
803 
804  }
805 
806  if (lseek(d_cache_info_fd, 0, SEEK_SET) == -1)
807  throw BESInternalError("Could not rewind to front of cache info file.", __FILE__, __LINE__);
808 
809  if(write(d_cache_info_fd, &computed_size, sizeof(unsigned long long)) != sizeof(unsigned long long))
810  throw BESInternalError("Could not write size info to the cache info file!", __FILE__, __LINE__);
811 #if 0
812  if (BESISDEBUG( "cache_contents" )) {
813  contents.clear();
814  computed_size = m_collect_cache_dir_info(contents);
815  BESDEBUG("cache", "AFTER Purge " << computed_size/BYTES_PER_MEG << endl );
816  CacheFiles::iterator ti = contents.begin();
817  CacheFiles::iterator te = contents.end();
818  for (; ti != te; ti++) {
819  BESDEBUG("cache", (*ti).time << ": " << (*ti).name << ": size " << (*ti).size/BYTES_PER_MEG << endl );
820  }
821  }
822 #endif
823  unlock_cache();
824  }
825  catch(...) {
826  unlock_cache();
827  throw;
828  }
829 }
830 
842 void BESFileLockingCache::purge_file(const string &file)
843 {
844  BESDEBUG("cache", "BESFileLockingCache::purge_file() - starting the purge" << endl);
845 
846  try {
848 
849  // Grab an exclusive lock on the file
850  int cfile_fd;
851  if (getExclusiveLock(file, cfile_fd)) {
852  // Get the file's size
853  unsigned long long size = 0;
854  struct stat buf;
855  if (stat(file.c_str(), &buf) == 0) {
856  size = buf.st_size;
857  }
858 
859  BESDEBUG("cache", "BESFileLockingCache::purge_file() - " << file << " removed." << endl );
860 
861  if (unlink(file.c_str()) != 0)
862  throw BESInternalError("Unable to purge the file " + file + " from the cache: " + get_errno(), __FILE__, __LINE__);
863 
864  unlock(cfile_fd);
865 
866  unsigned long long cache_size = get_cache_size() - size;
867 
868  if (lseek(d_cache_info_fd, 0, SEEK_SET) == -1)
869  throw BESInternalError("Could not rewind to front of cache info file.", __FILE__, __LINE__);
870 
871  if (write(d_cache_info_fd, &cache_size, sizeof(unsigned long long)) != sizeof(unsigned long long))
872  throw BESInternalError("Could not write size info to the cache info file!", __FILE__, __LINE__);
873  }
874 
875  unlock_cache();
876  }
877  catch (...) {
878  unlock_cache();
879  throw;
880  }
881 }
882 
883 
885  return d_prefix;
886 }
887 
889  return d_cache_dir;
890 }
891 
892 
893 
901 void BESFileLockingCache::dump(ostream &strm) const
902 {
903  strm << BESIndent::LMarg << "BESFileLockingCache::dump - (" << (void *) this << ")" << endl;
905  strm << BESIndent::LMarg << "cache dir: " << d_cache_dir << endl;
906  strm << BESIndent::LMarg << "prefix: " << d_prefix << endl;
907  strm << BESIndent::LMarg << "size (bytes): " << d_max_cache_size_in_bytes << endl;
909 }
virtual void unlock_cache()
Unlock the cache info file.
#define BESISDEBUG(x)
macro used to determine if the specified debug context is set
Definition: BESDebug.h:83
exception thrown if inernal error encountered
time_t time
virtual bool create_and_lock(const string &target, int &fd)
Create a file in the cache and lock it for write access.
STL namespace.
const string getCacheDirectory()
unsigned long long size
string name
virtual unsigned long long get_cache_size()
Get the cache size.
static void Indent()
Definition: BESIndent.cc:38
void initialize(const string &cache_dir, const string &prefix, unsigned long long size)
virtual void dump(ostream &strm) const
dumps information about this object
#define NULL
Definition: wcsUtil.h:65
static ostream & LMarg(ostream &strm)
Definition: BESIndent.cc:73
virtual void purge_file(const string &file)
Purge a single file from the cache.
std::list< cache_entry > CacheFiles
#define min(a, b)
Definition: os_utils.h:71
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...
virtual void lock_cache_write()
Get an exclusive lock on the 'cache info' file.
virtual string get_cache_file_name(const string &src, bool mangle=true)
Build the name of file that will holds the uncompressed data from 'src' in the cache.
const string getCacheFilePrefix()
virtual bool get_read_lock(const string &target, int &fd)
Get a read-only lock on the file if it exists.
virtual void update_and_purge(const string &new_file)
Purge files from the cache.
virtual unsigned long long update_cache_info(const string &target)
Update the cache info file to include 'target'.
virtual void lock_cache_read()
Get a shared lock on the 'cache info' file.
virtual void exclusive_to_shared_lock(int fd)
Transfer from an exclusive lock to a shared lock.
#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 bool getExclusiveLock(string file_name, int &ref_fd)
Get an exclusive read/write lock on an existing file.
virtual void unlock_and_close(const string &target)
Unlock the named file.