libdap Updated for version 3.21.1
libdap4 is an implementation of OPeNDAP's DAP protocol.
DAPCache3.cc
Go to the documentation of this file.
1// DAPCache3.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// Copyright (c) 2012 OPeNDAP, Inc
9// Author: James Gallagher <jgallagher@opendap.org>
10// Patrick West <pwest@ucar.edu> and Jose Garcia <jgarcia@ucar.edu>
11//
12// This library is free software; you can redistribute it and/or
13// modify it under the terms of the GNU Lesser General Public
14// License as published by the Free Software Foundation; either
15// version 2.1 of the License, or (at your option) any later version.
16//
17// This library is distributed in the hope that it will be useful,
18// but WITHOUT ANY WARRANTY; without even the implied warranty of
19// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20// Lesser General Public License for more details.
21//
22// You should have received a copy of the GNU Lesser General Public
23// License along with this library; if not, write to the Free Software
24// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25//
26// You can contact University Corporation for Atmospheric Research at
27// 3080 Center Green Drive, Boulder, CO 80301
28
29#include "config.h"
30
31#include <dirent.h>
32#include <fcntl.h>
33#include <sys/file.h>
34#include <sys/stat.h>
35#include <unistd.h>
36
37#ifdef HAVE_STDLIB_H
38#include <stdlib.h>
39#endif
40
41#include <cerrno>
42#include <cstring>
43#include <sstream>
44#include <string>
45#include <vector>
46
47#include "DAPCache3.h"
48
49// #define DODS_DEBUG
50
51#include "DapIndent.h"
52#include "InternalErr.h"
53#include "debug.h"
54
55#if 0
56#include "BESInternalError.h"
57#include "BESSyntaxUserError.h"
58
59#include "BESDebug.h"
60#include "BESLog.h"
61#include "TheBESKeys.h"
62#endif
63using namespace std;
64using namespace libdap;
65
66namespace libdap {
67
68// conversion factor
69static const unsigned long long BYTES_PER_MEG = 1048576ULL;
70
71// Max cache size in megs, so we can check the user input and warn.
72// 2^64 / 2^20 == 2^44
73static const unsigned long long MAX_CACHE_SIZE_IN_MEGABYTES = (1ULL << 44);
74
75DAPCache3 *DAPCache3::d_instance = 0;
76
90DAPCache3::DAPCache3(const string &cache_dir, const string &prefix, unsigned long long size)
91 : d_cache_dir(cache_dir), d_prefix(prefix), d_max_cache_size_in_bytes(size) {
92 m_initialize_cache_info();
93}
94
95void DAPCache3::delete_instance() {
96 DBG(cerr << "DAPCache3::delete_instance() - Deleting singleton DAPCache3 instance." << endl);
97 delete d_instance;
98 d_instance = 0;
99}
100
101#if 0
102// The BESCache3 code is a singleton that assumes it's running in the absence of threads but that
103// the cache is shared by several processes, each of which have their own instance of BESCache3.
115BESCache3 *
116BESCache3::get_instance(BESKeys *keys, const string &cache_dir_key, const string &prefix_key, const string &size_key)
117{
118 if (d_instance == 0)
119 d_instance = new BESCache3(keys, cache_dir_key, prefix_key, size_key);
120
121 return d_instance;
122}
123#endif
135DAPCache3 *DAPCache3::get_instance(const string &cache_dir, const string &prefix, unsigned long long size) {
136 if (d_instance == 0) {
137 d_instance = new DAPCache3(cache_dir, prefix, size);
138#if HAVE_ATEXIT
139 atexit(delete_instance);
140#endif
141 }
142 return d_instance;
143}
144
149 if (d_instance == 0)
150 throw InternalErr(__FILE__, __LINE__, "Tried to get the DAPCache3 instance, but it hasn't been created yet");
151
152 return d_instance;
153}
154
155static inline string get_errno() {
156 char *s_err = strerror(errno);
157 if (s_err)
158 return s_err;
159 else
160 return "Unknown error.";
161}
162
163// Build a lock of a certain type.
164static inline struct flock *lock(int type) {
165 static struct flock lock;
166 lock.l_type = type;
167 lock.l_whence = SEEK_SET;
168 lock.l_start = 0;
169 lock.l_len = 0;
170 lock.l_pid = getpid();
171
172 return &lock;
173}
174
175inline void DAPCache3::m_record_descriptor(const string &file, int fd) {
176 DBG(cerr << "DAP Cache: recording descriptor: " << file << ", " << fd << endl);
177 d_locks.insert(std::pair<string, int>(file, fd));
178}
179
180inline int DAPCache3::m_get_descriptor(const string &file) {
181 FilesAndLockDescriptors::iterator i = d_locks.find(file);
182 int fd = i->second;
183 DBG(cerr << "DAP Cache: getting descriptor: " << file << ", " << fd << endl);
184 d_locks.erase(i);
185 return fd;
186}
187
193static void unlock(int fd) {
194 if (fcntl(fd, F_SETLK, lock(F_UNLCK)) == -1) {
195 throw InternalErr(__FILE__, __LINE__, "An error occurred trying to unlock the file" + get_errno());
196 }
197
198 if (close(fd) == -1)
199 throw InternalErr(__FILE__, __LINE__, "Could not close the (just) unlocked file.");
200}
201
214static bool getSharedLock(const string &file_name, int &ref_fd) {
215 DBG(cerr << "getSharedLock: " << file_name << endl);
216
217 int fd;
218 if ((fd = open(file_name.c_str(), O_RDONLY)) < 0) {
219 switch (errno) {
220 case ENOENT:
221 return false;
222
223 default:
224 throw InternalErr(__FILE__, __LINE__, get_errno());
225 }
226 }
227
228 struct flock *l = lock(F_RDLCK);
229 if (fcntl(fd, F_SETLKW, l) == -1) {
230 close(fd);
231 ostringstream oss;
232 oss << "cache process: " << l->l_pid << " triggered a locking error: " << get_errno();
233 throw InternalErr(__FILE__, __LINE__, oss.str());
234 }
235
236 DBG(cerr << "getSharedLock exit: " << file_name << endl);
237
238 // Success
239 ref_fd = fd;
240 return true;
241}
242
255static bool getExclusiveLock(string file_name, int &ref_fd) {
256 DBG(cerr << "getExclusiveLock: " << file_name << endl);
257
258 int fd;
259 if ((fd = open(file_name.c_str(), O_RDWR)) < 0) {
260 switch (errno) {
261 case ENOENT:
262 return false;
263
264 default:
265 throw InternalErr(__FILE__, __LINE__, get_errno());
266 }
267 }
268
269 struct flock *l = lock(F_WRLCK);
270 if (fcntl(fd, F_SETLKW, l) == -1) {
271 close(fd);
272 ostringstream oss;
273 oss << "cache process: " << l->l_pid << " triggered a locking error: " << get_errno();
274 throw InternalErr(__FILE__, __LINE__, oss.str());
275 }
276
277 DBG(cerr << "getExclusiveLock exit: " << file_name << endl);
278
279 // Success
280 ref_fd = fd;
281 return true;
282}
283
295static bool getExclusiveLockNB(string file_name, int &ref_fd) {
296 DBG(cerr << "getExclusiveLock_nonblocking: " << file_name << endl);
297
298 int fd;
299 if ((fd = open(file_name.c_str(), O_RDWR)) < 0) {
300 switch (errno) {
301 case ENOENT:
302 return false;
303
304 default:
305 throw InternalErr(__FILE__, __LINE__, get_errno());
306 }
307 }
308
309 struct flock *l = lock(F_WRLCK);
310 if (fcntl(fd, F_SETLK, l) == -1) {
311 switch (errno) {
312 case EAGAIN:
313 DBG(cerr << "getExclusiveLock_nonblocking exit (false): " << file_name << " by: " << l->l_pid << endl);
314 close(fd);
315 return false;
316
317 default: {
318 close(fd);
319 ostringstream oss;
320 oss << "cache process: " << l->l_pid << " triggered a locking error: " << get_errno();
321 throw InternalErr(__FILE__, __LINE__, oss.str());
322 }
323 }
324 }
325
326 DBG(cerr << "getExclusiveLock_nonblocking exit (true): " << file_name << endl);
327
328 // Success
329 ref_fd = fd;
330 return true;
331}
332
346static bool createLockedFile(string file_name, int &ref_fd) {
347 DBG(cerr << "createLockedFile: " << file_name << endl);
348
349 int fd;
350 if ((fd = open(file_name.c_str(), O_CREAT | O_EXCL | O_RDWR, 0666)) < 0) {
351 switch (errno) {
352 case EEXIST:
353 return false;
354
355 default:
356 throw InternalErr(__FILE__, __LINE__, get_errno());
357 }
358 }
359
360 struct flock *l = lock(F_WRLCK);
361 if (fcntl(fd, F_SETLKW, l) == -1) {
362 close(fd);
363 ostringstream oss;
364 oss << "cache process: " << l->l_pid << " triggered a locking error: " << get_errno();
365 throw InternalErr(__FILE__, __LINE__, oss.str());
366 }
367
368 DBG(cerr << "createLockedFile exit: " << file_name << endl);
369
370 // Success
371 ref_fd = fd;
372 return true;
373}
374
376void DAPCache3::m_check_ctor_params() {
377 if (d_cache_dir.empty()) {
378 string err = "The cache directory was not specified, must be non-empty";
379 throw InternalErr(__FILE__, __LINE__, err);
380 }
381
382 // TODO New feature: Makes the directory f it does not exist
383 struct stat buf;
384 int statret = stat(d_cache_dir.c_str(), &buf);
385 if (statret != 0 || !S_ISDIR(buf.st_mode)) {
386 // Try to make the directory
387 int status = mkdir(d_cache_dir.c_str(), 0775);
388 if (status != 0) {
389 string err = "The cache directory " + d_cache_dir + " does not exist or could not be created.";
390 throw InternalErr(__FILE__, __LINE__, err);
391 }
392 }
393
394 if (d_prefix.empty()) {
395 string err = "The cache file prefix was not specified, must not be empty";
396 throw InternalErr(__FILE__, __LINE__, err);
397 }
398
399 if (d_max_cache_size_in_bytes <= 0) {
400 string err = "The cache size was not specified, must be greater than zero";
401 throw InternalErr(__FILE__, __LINE__, err);
402 }
403#if 0
404 // redundant check
405
406 // If the user specifies a cache that is too large,
407 // it is a user exception and we should tell them.
408 if (d_max_cache_size_in_bytes > MAX_CACHE_SIZE_IN_MEGABYTES) {
409 std::ostringstream msg;
410 msg << "The specified cache size was larger than the max cache size of: " << MAX_CACHE_SIZE_IN_MEGABYTES
411 << " (was " << d_max_cache_size_in_bytes << ").";
412 throw InternalErr(__FILE__, __LINE__, msg.str());
413 }
414#endif
415 DBG(cerr << "DAP Cache: directory " << d_cache_dir << ", prefix " << d_prefix << ", max size "
416 << d_max_cache_size_in_bytes << endl);
417}
418
420void DAPCache3::m_initialize_cache_info() {
421 // The value set in configuration files, etc., is the size in megabytes. The private
422 // variable holds the size in bytes (converted below).
423 d_max_cache_size_in_bytes = min(d_max_cache_size_in_bytes, MAX_CACHE_SIZE_IN_MEGABYTES);
424 d_max_cache_size_in_bytes *= BYTES_PER_MEG;
425 d_target_size = d_max_cache_size_in_bytes * 0.8;
426
427 m_check_ctor_params(); // Throws InternalErr on error.
428
429 d_cache_info = d_cache_dir + "/dap.cache.info";
430
431 // See if we can create it. If so, that means it doesn't exist. So make it and
432 // set the cache initial size to zero.
433 if (createLockedFile(d_cache_info, d_cache_info_fd)) {
434 // initialize the cache size to zero
435 unsigned long long size = 0;
436 if (write(d_cache_info_fd, &size, sizeof(unsigned long long)) != sizeof(unsigned long long))
437 throw InternalErr(__FILE__, __LINE__, "Could not write size info to the cache info file in startup!");
438
439 // This leaves the d_cache_info_fd file descriptor open
440 unlock_cache();
441 } else {
442 if ((d_cache_info_fd = open(d_cache_info.c_str(), O_RDWR)) == -1) {
443 throw InternalErr(__FILE__, __LINE__, get_errno());
444 }
445 }
446
447 DBG(cerr << "d_cache_info_fd: " << d_cache_info_fd << endl);
448}
449
450#if 0
465BESCache3::BESCache3(BESKeys *keys, const string &cache_dir_key, const string &prefix_key, const string &size_key) :
466 d_max_cache_size_in_bytes(0)
467{
468 bool found = false;
469 keys->get_value(cache_dir_key, d_cache_dir, found);
470 if (!found)
471 throw BESSyntaxUserError("The cache directory key " + cache_dir_key + " was not found in the BES configuration file", __FILE__, __LINE__);
472
473 found = false;
474 keys->get_value(prefix_key, d_prefix, found);
475 if (!found)
476 throw BESSyntaxUserError("The prefix key " + prefix_key + " was not found in the BES configuration file", __FILE__, __LINE__);
477
478 found = false;
479 string cache_size_str;
480 keys->get_value(size_key, cache_size_str, found);
481 if (!found)
482 throw BESSyntaxUserError("The size key " + size_key + " was not found in the BES configuration file", __FILE__, __LINE__);
483
484 std::istringstream is(cache_size_str);
485 is >> d_max_cache_size_in_bytes;
486
487 m_initialize_cache_info();
488}
489#endif
490
506string DAPCache3::get_cache_file_name(const string &src, bool mangle) {
507 string target = src;
508
509 if (mangle) {
510 if (target.at(0) == '/') {
511 target = src.substr(1, target.length() - 1);
512 }
513 string::size_type slash = 0;
514 while ((slash = target.find('/')) != string::npos) {
515 target.replace(slash, 1, 1, DAPCache3::DAP_CACHE_CHAR);
516 }
517 string::size_type last_dot = target.rfind('.');
518 if (last_dot != string::npos) {
519 target = target.substr(0, last_dot);
520 }
521 }
522 DBG(cerr << " d_cache_dir: '" << d_cache_dir << "'" << endl);
523 DBG(cerr << " d_prefix: '" << d_prefix << "'" << endl);
524 DBG(cerr << " target: '" << target << "'" << endl);
525
526 return d_cache_dir + "/" + d_prefix + DAPCache3::DAP_CACHE_CHAR + target;
527}
528
546bool DAPCache3::get_read_lock(const string &target, int &fd) {
548
549 bool status = getSharedLock(target, fd);
550
551 DBG(cerr << "DAP Cache: read_lock: " << target << "(" << status << ")" << endl);
552
553 if (status)
554 m_record_descriptor(target, fd);
555
556 unlock_cache();
557
558 return status;
559}
560
573bool DAPCache3::create_and_lock(const string &target, int &fd) {
575
576 bool status = createLockedFile(target, fd);
577
578 DBG(cerr << "DAP Cache: create_and_lock: " << target << "(" << status << ")" << endl);
579
580 if (status)
581 m_record_descriptor(target, fd);
582
583 unlock_cache();
584
585 return status;
586}
587
602 struct flock lock;
603 lock.l_type = F_RDLCK;
604 lock.l_whence = SEEK_SET;
605 lock.l_start = 0;
606 lock.l_len = 0;
607 lock.l_pid = getpid();
608
609 if (fcntl(fd, F_SETLKW, &lock) == -1) {
610 throw InternalErr(__FILE__, __LINE__, get_errno());
611 }
612}
613
623 DBG(cerr << "lock_cache - d_cache_info_fd: " << d_cache_info_fd << endl);
624
625 if (fcntl(d_cache_info_fd, F_SETLKW, lock(F_WRLCK)) == -1) {
626 throw InternalErr(__FILE__, __LINE__, "An error occurred trying to lock the cache-control file" + get_errno());
627 }
628}
629
634 DBG(cerr << "lock_cache - d_cache_info_fd: " << d_cache_info_fd << endl);
635
636 if (fcntl(d_cache_info_fd, F_SETLKW, lock(F_RDLCK)) == -1) {
637 throw InternalErr(__FILE__, __LINE__, "An error occurred trying to lock the cache-control file" + get_errno());
638 }
639}
640
647 DBG(cerr << "DAP Cache: unlock: cache_info (fd: " << d_cache_info_fd << ")" << endl);
648
649 if (fcntl(d_cache_info_fd, F_SETLK, lock(F_UNLCK)) == -1) {
650 throw InternalErr(__FILE__, __LINE__,
651 "An error occurred trying to unlock the cache-control file" + get_errno());
652 }
653}
654
666void DAPCache3::unlock_and_close(const string &file_name) {
667 DBG(cerr << "DAP Cache: unlock file: " << file_name << endl);
668
669 unlock(m_get_descriptor(file_name));
670}
671
678 DBG(cerr << "DAP Cache: unlock fd: " << fd << endl);
679
680 unlock(fd);
681
682 DBG(cerr << "DAP Cache: unlock " << fd << " Success" << endl);
683}
684
695unsigned long long DAPCache3::update_cache_info(const string &target) {
696 try {
698
699 if (lseek(d_cache_info_fd, 0, SEEK_SET) == -1)
700 throw InternalErr(__FILE__, __LINE__, "Could not rewind to front of cache info file.");
701
702 // read the size from the cache info file
703 unsigned long long current_size;
704 if (read(d_cache_info_fd, &current_size, sizeof(unsigned long long)) != sizeof(unsigned long long))
705 throw InternalErr(__FILE__, __LINE__, "Could not get read size info from the cache info file!");
706
707 struct stat buf;
708 int statret = stat(target.c_str(), &buf);
709 if (statret == 0)
710 current_size += buf.st_size;
711 else
712 throw InternalErr(__FILE__, __LINE__,
713 "Could not read the size of the new file: " + target + " : " + get_errno());
714
715 DBG(cerr << "DAP Cache: cache size updated to: " << current_size << endl);
716
717 if (lseek(d_cache_info_fd, 0, SEEK_SET) == -1)
718 throw InternalErr(__FILE__, __LINE__, "Could not rewind to front of cache info file.");
719
720 if (write(d_cache_info_fd, &current_size, sizeof(unsigned long long)) != sizeof(unsigned long long))
721 throw InternalErr(__FILE__, __LINE__, "Could not write size info from the cache info file!");
722
723 unlock_cache();
724 return current_size;
725 } catch (...) {
726 unlock_cache();
727 throw;
728 }
729}
730
735bool DAPCache3::cache_too_big(unsigned long long current_size) const {
736 return current_size > d_max_cache_size_in_bytes;
737}
738
746unsigned long long DAPCache3::get_cache_size() {
747 try {
749
750 if (lseek(d_cache_info_fd, 0, SEEK_SET) == -1)
751 throw InternalErr(__FILE__, __LINE__, "Could not rewind to front of cache info file.");
752 // read the size from the cache info file
753 unsigned long long current_size;
754 if (read(d_cache_info_fd, &current_size, sizeof(unsigned long long)) != sizeof(unsigned long long))
755 throw InternalErr(__FILE__, __LINE__, "Could not get read size info from the cache info file!");
756
757 unlock_cache();
758 return current_size;
759 } catch (...) {
760 unlock_cache();
761 throw;
762 }
763}
764
765static bool entry_op(cache_entry &e1, cache_entry &e2) { return e1.time < e2.time; }
766
768unsigned long long DAPCache3::m_collect_cache_dir_info(CacheFiles &contents) {
769 DIR *dip = opendir(d_cache_dir.c_str());
770 if (!dip)
771 throw InternalErr(__FILE__, __LINE__, "Unable to open cache directory " + d_cache_dir);
772
773 struct dirent *dit;
774 vector<string> files;
775 // go through the cache directory and collect all of the files that
776 // start with the matching prefix
777 while ((dit = readdir(dip)) != NULL) {
778 string dirEntry = dit->d_name;
779 if (dirEntry.compare(0, d_prefix.length(), d_prefix) == 0) {
780 files.push_back(d_cache_dir + "/" + dirEntry);
781 }
782 }
783
784 closedir(dip);
785
786 unsigned long long current_size = 0;
787 struct stat buf;
788 for (vector<string>::iterator file = files.begin(); file != files.end(); ++file) {
789 if (stat(file->c_str(), &buf) == 0) {
790 current_size += buf.st_size;
791 cache_entry entry;
792 entry.name = *file;
793 entry.size = buf.st_size;
794 entry.time = buf.st_atime;
795 // Sanity check; Removed after initial testing since some files might be zero bytes
796#if 0
797 if (entry.size == 0)
798 throw InternalErr(__FILE__, __LINE__, "Zero-byte file found in cache. " + *file);
799#endif
800 contents.push_back(entry);
801 }
802 }
803
804 // Sort so smaller (older) times are first.
805 contents.sort(entry_op);
806
807 return current_size;
808}
809
821void DAPCache3::update_and_purge(const string &new_file) {
822 DBG(cerr << "purge - starting the purge" << endl);
823
824 try {
826
827 CacheFiles contents;
828 unsigned long long computed_size = m_collect_cache_dir_info(contents);
829#if 0
830 if (BESISDEBUG( "cache_contents" )) {
831 DBG(endl << "BEFORE Purge " << computed_size/BYTES_PER_MEG << endl );
832 CacheFiles::iterator ti = contents.begin();
833 CacheFiles::iterator te = contents.end();
834 for (; ti != te; ti++) {
835 DBG((*ti).time << ": " << (*ti).name << ": size " << (*ti).size/BYTES_PER_MEG << endl );
836 }
837 }
838#endif
839 DBG(cerr << "purge - current and target size (in MB) " << computed_size / BYTES_PER_MEG << ", "
840 << d_target_size / BYTES_PER_MEG << endl);
841
842 // This deletes files and updates computed_size
843 if (cache_too_big(computed_size)) {
844
845 // d_target_size is 80% of the maximum cache size.
846 // Grab the first which is the oldest in terms of access time.
847 CacheFiles::iterator i = contents.begin();
848 while (i != contents.end() && computed_size > d_target_size) {
849 // Grab an exclusive lock but do not block - if another process has the file locked
850 // just move on to the next file. Also test to see if the current file is the file
851 // this process just added to the cache - don't purge that!
852 int cfile_fd;
853 if (i->name != new_file && getExclusiveLockNB(i->name, cfile_fd)) {
854 DBG(cerr << "purge: " << i->name << " removed." << endl);
855
856 if (unlink(i->name.c_str()) != 0)
857 throw InternalErr(__FILE__, __LINE__,
858 "Unable to purge the file " + i->name + " from the cache: " + get_errno());
859
860 unlock(cfile_fd);
861 computed_size -= i->size;
862 }
863#if 0
864 else {
865 // This information is useful when debugging... Might comment out for production
866 DBG(cerr << "purge: " << i->name << " is in use." << endl );
867 }
868#endif
869 ++i;
870
871 DBG(cerr << "purge - current and target size (in MB) " << computed_size / BYTES_PER_MEG << ", "
872 << d_target_size / BYTES_PER_MEG << endl);
873 }
874 }
875
876 if (lseek(d_cache_info_fd, 0, SEEK_SET) == -1)
877 throw InternalErr(__FILE__, __LINE__, "Could not rewind to front of cache info file.");
878
879 if (write(d_cache_info_fd, &computed_size, sizeof(unsigned long long)) != sizeof(unsigned long long))
880 throw InternalErr(__FILE__, __LINE__, "Could not write size info to the cache info file!");
881#if 0
882 if (BESISDEBUG( "cache_contents" )) {
883 contents.clear();
884 computed_size = m_collect_cache_dir_info(contents);
885 DBG(endl << "AFTER Purge " << computed_size/BYTES_PER_MEG << endl );
886 CacheFiles::iterator ti = contents.begin();
887 CacheFiles::iterator te = contents.end();
888 for (; ti != te; ti++) {
889 DBG((*ti).time << ": " << (*ti).name << ": size " << (*ti).size/BYTES_PER_MEG << endl );
890 }
891 }
892#endif
893 unlock_cache();
894 } catch (...) {
895 unlock_cache();
896 throw;
897 }
898}
899
911void DAPCache3::purge_file(const string &file) {
912 DBG(cerr << "purge_file - starting the purge" << endl);
913
914 try {
916
917 // Grab an exclusive lock on the file
918 int cfile_fd;
919 if (getExclusiveLock(file, cfile_fd)) {
920 // Get the file's size
921 unsigned long long size = 0;
922 struct stat buf;
923 if (stat(file.c_str(), &buf) == 0) {
924 size = buf.st_size;
925 }
926
927 DBG(cerr << "purge_file: " << file << " removed." << endl);
928
929 if (unlink(file.c_str()) != 0)
930 throw InternalErr(__FILE__, __LINE__,
931 "Unable to purge the file " + file + " from the cache: " + get_errno());
932
933 unlock(cfile_fd);
934
935 unsigned long long cache_size = get_cache_size() - size;
936
937 if (lseek(d_cache_info_fd, 0, SEEK_SET) == -1)
938 throw InternalErr(__FILE__, __LINE__, "Could not rewind to front of cache info file.");
939
940 if (write(d_cache_info_fd, &cache_size, sizeof(unsigned long long)) != sizeof(unsigned long long))
941 throw InternalErr(__FILE__, __LINE__, "Could not write size info to the cache info file!");
942 }
943
944 unlock_cache();
945 } catch (...) {
946 unlock_cache();
947 throw;
948 }
949}
950
958void DAPCache3::dump(ostream &strm) const {
959 strm << DapIndent::LMarg << "DAPCache3::dump - (" << (void *)this << ")" << endl;
961 strm << DapIndent::LMarg << "cache dir: " << d_cache_dir << endl;
962 strm << DapIndent::LMarg << "prefix: " << d_prefix << endl;
963 strm << DapIndent::LMarg << "size (bytes): " << d_max_cache_size_in_bytes << endl;
965}
966
967} // namespace libdap
Implementation of a caching mechanism for compressed data. This cache uses simple advisory locking fo...
Definition DAPCache3.h:82
virtual unsigned long long get_cache_size()
Get the cache size. Read the size information from the cache info file and return it....
Definition DAPCache3.cc:746
string get_cache_file_name(const string &src, bool mangle=true)
Definition DAPCache3.cc:506
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 DAPCache3.cc:735
virtual void purge_file(const string &file)
Purge a single file from the cache.
Definition DAPCache3.cc:911
virtual bool get_read_lock(const string &target, int &fd)
Get a read-only lock on the file if it exists.
Definition DAPCache3.cc:546
virtual void unlock_cache()
Definition DAPCache3.cc:646
virtual void dump(ostream &strm) const
dumps information about this object
Definition DAPCache3.cc:958
virtual void exclusive_to_shared_lock(int fd)
Transfer from an exclusive lock to a shared lock. If the file has an exclusive write lock on it,...
Definition DAPCache3.cc:601
virtual void lock_cache_read()
Definition DAPCache3.cc:633
virtual void unlock_and_close(const string &target)
virtual unsigned long long update_cache_info(const string &target)
Update the cache info file to include 'target'.
Definition DAPCache3.cc:695
static DAPCache3 * get_instance()
Definition DAPCache3.cc:148
virtual void update_and_purge(const string &new_file)
Purge files from the cache.
Definition DAPCache3.cc:821
virtual void lock_cache_write()
Definition DAPCache3.cc:622
virtual bool create_and_lock(const string &target, int &fd)
Create a file in the cache and lock it for write access. If the file does not exist,...
Definition DAPCache3.cc:573
static ostream & LMarg(ostream &strm)
Definition DapIndent.cc:61
static void Indent()
Definition DapIndent.cc:44
static void UnIndent()
Definition DapIndent.cc:46
A class for software fault reporting.
Definition InternalErr.h:61
#define DBG(x)
Definition debug.h:58
top level DAP object to house generic methods
Definition AISConnect.cc:30
std::list< cache_entry > CacheFiles
Definition DAPCache3.h:57
Definition DAPCache3.h:51
unsigned long long size
Definition DAPCache3.h:53
string name
Definition DAPCache3.h:52
time_t time
Definition DAPCache3.h:54