36 #include <sys/types.h> 58 #define BES_CACHE_CHAR '#' 60 typedef struct _cache_entry
67 BESCache::check_ctor_params()
69 if( _cache_dir.empty() )
71 string err =
"The cache directory was not specified, must be non-empty";
76 int statret = stat( _cache_dir.c_str(), &buf ) ;
77 if( statret != 0 || ! S_ISDIR(buf.st_mode) )
79 string err =
"The cache directory " + _cache_dir +
" does not exist" ;
85 string err =
"The cache file prefix was not specified, must be non-empty" ;
89 if( _cache_size == 0 )
91 string err =
"The cache size was not specified, must be non-zero" ;
98 if( _cache_size > 4095 ) _cache_size = 4095 ;
100 BESDEBUG(
"bes",
"BES Cache: directory " << _cache_dir
101 <<
", prefix " << _prefix
102 <<
", max size " << _cache_size << endl ) ;
114 BESCache::BESCache(
const string &cache_dir,
115 const string &prefix,
117 : _cache_dir( cache_dir ),
140 const string &cache_dir_key,
141 const string &prefix_key,
142 const string &size_key )
147 keys.
get_value( cache_dir_key, _cache_dir, found ) ;
150 string err =
"The cache directory key " + cache_dir_key
151 +
" was not found in the BES configuration file" ;
156 keys.
get_value( prefix_key, _prefix, found ) ;
159 string err =
"The prefix key " + prefix_key
160 +
" was not found in the BES configuration file" ;
165 string cache_size_str ;
166 keys.
get_value( size_key, cache_size_str, found ) ;
169 string err =
"The size key " + size_key
170 +
" was not found in the BES configuration file" ;
174 std::istringstream is( cache_size_str ) ;
195 bool got_lock = true ;
198 string lock_file = _cache_dir +
"/lock" ;
199 unsigned int tries = 0 ;
200 _lock_fd = open( lock_file.c_str(),
202 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ) ;
203 while( _lock_fd < 0 && got_lock )
206 if( tries > num_tries )
214 _lock_fd = open( lock_file.c_str(),
216 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ) ;
225 string err =
"The cache dir " + _cache_dir +
" is already locked" ;
243 bool unlocked = true ;
246 string lock_file = _cache_dir +
"/lock" ;
248 (void)unlink( lock_file.c_str() ) ;
273 string tmp_target = src ;
277 if( tmp_target.at(0) ==
'/' )
279 tmp_target = src.substr( 1, tmp_target.length() - 1 ) ;
281 string::size_type slash = 0 ;
282 while( ( slash = tmp_target.find(
'/' ) ) != string::npos )
286 string::size_type last_dot = tmp_target.rfind(
'.' ) ;
287 if( last_dot != string::npos )
289 tmp_target = tmp_target.substr( 0, last_dot ) ;
292 target = _cache_dir +
"/" + _prefix +
BES_CACHE_CHAR + tmp_target ;
296 int statret = stat( target.c_str(), &buf ) ;
316 unsigned int max_size = _cache_size * 1048576 ;
318 unsigned int size = 0 ;
319 unsigned int avg_size = 0 ;
320 unsigned int num_files_in_cache = 0 ;
321 time_t curr_time = time( NULL ) ;
324 multimap<double,cache_entry,greater<double> > contents ;
331 DIR *dip = opendir( _cache_dir.c_str() ) ;
335 while( ( dit = readdir( dip ) ) != NULL )
337 string dirEntry = dit->d_name ;
338 if( dirEntry.compare( 0, match_prefix.length(), match_prefix ) == 0)
342 string fullPath = _cache_dir +
"/" + dirEntry ;
343 int statret = stat( fullPath.c_str(), &buf ) ;
346 size += buf.st_size ;
349 time_t file_time = buf.st_atime ;
354 double time_diff = difftime( curr_time, file_time ) ;
356 entry.name = fullPath ;
357 entry.size = buf.st_size ;
358 contents.insert( pair<double,cache_entry>( time_diff, entry ) );
360 num_files_in_cache++ ;
367 if( num_files_in_cache ) avg_size = size / num_files_in_cache ;
369 BESDEBUG(
"bes",
"cache size = " << size << endl ) ;
370 BESDEBUG(
"bes",
"avg size = " << avg_size << endl ) ;
371 BESDEBUG(
"bes",
"num files in cache = " 372 << num_files_in_cache << endl ) ;
375 BESDEBUG(
"bes", endl <<
"BEFORE" << endl ) ;
376 multimap<double,cache_entry,greater<double> >::iterator ti = contents.begin() ;
377 multimap<double,cache_entry,greater<double> >::iterator te = contents.end() ;
378 for( ; ti != te; ti++ )
380 BESDEBUG(
"bes", (*ti).first <<
": " << (*ti).second.name <<
": size " << (*ti).second.size << endl ) ;
388 multimap<double,cache_entry,greater<double> >::iterator i ;
389 if( (size+avg_size) > max_size )
393 while( (size+avg_size) > max_size )
395 i = contents.begin() ;
396 if( i == contents.end() )
407 BESDEBUG(
"bes",
"BESCache::purge - removing " 408 << (*i).second.name << endl ) ;
409 if(
remove( (*i).second.name.c_str() ) != 0 )
411 char *s_err = strerror( errno ) ;
412 string err =
"Unable to remove the file " 414 +
" from the cache: " ;
417 err.append( s_err ) ;
421 err.append(
"Unknown error" ) ;
425 size -= (*i).second.size ;
426 contents.erase( i ) ;
433 BESDEBUG(
"bes", endl <<
"AFTER" << endl ) ;
434 multimap<double,cache_entry,greater<double> >::iterator ti = contents.begin() ;
435 multimap<double,cache_entry,greater<double> >::iterator te = contents.end() ;
436 for( ; ti != te; ti++ )
438 BESDEBUG(
"bes", (*ti).first <<
": " << (*ti).second.name <<
": size " << (*ti).second.size << endl ) ;
444 string err =
"Unable to open cache directory " + _cache_dir ;
460 << (
void *)
this <<
")" << endl ;
#define BESISDEBUG(x)
macro used to determine if the specified debug context is set
#define MAX_LOCK_RETRY_MS
exception thrown if inernal error encountered
virtual bool lock(unsigned int retry_ms, unsigned int num_tries)
lock the cache using a file lock
virtual void purge()
Check to see if the cache size exceeds the size specified in the constructor and purge older files un...
virtual void dump(ostream &strm) const
dumps information about this object
error thrown if there is a user syntax error in the request or any other user error ...
mapping of key/value pairs defining different behaviors of an application.
static ostream & LMarg(ostream &strm)
virtual bool unlock()
unlock the cache
void get_value(const string &s, string &val, bool &found)
Retrieve the value of a given key, if set.
virtual bool is_cached(const string &src, string &target)
Determine if the file specified by src is cached.
struct _cache_entry cache_entry
#define BESDEBUG(x, y)
macro used to send debug information to the debug stream