00001 /* 00002 * Phusion Passenger - http://www.modrails.com/ 00003 * Copyright (C) 2009 Phusion 00004 * 00005 * Phusion Passenger is a trademark of Hongli Lai & Ninh Bui. 00006 * 00007 * This program is free software; you can redistribute it and/or modify 00008 * it under the terms of the GNU General Public License as published by 00009 * the Free Software Foundation; version 2 of the License. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License along 00017 * with this program; if not, write to the Free Software Foundation, Inc., 00018 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 00019 */ 00020 #ifndef _PASSENGER_CACHED_FILE_STAT_H_ 00021 #define _PASSENGER_CACHED_FILE_STAT_H_ 00022 00023 #include <sys/types.h> 00024 #include <sys/stat.h> 00025 #include <unistd.h> 00026 #include <time.h> 00027 00028 #ifdef __cplusplus 00029 00030 #include <errno.h> 00031 #include <string> 00032 #include <oxt/system_calls.hpp> 00033 00034 #include "SystemTime.h" 00035 00036 namespace Passenger { 00037 00038 using namespace std; 00039 using namespace oxt; 00040 00041 /** 00042 * CachedFileStat allows one to stat() a file at a throttled rate, in order 00043 * to minimize stress on the filesystem. It does this by caching the old stat 00044 * data for a specified amount of time. 00045 */ 00046 class CachedFileStat { 00047 private: 00048 /** The last return value of stat(). */ 00049 int last_result; 00050 00051 /** The errno set by the last stat() call. */ 00052 int last_errno; 00053 00054 /** The filename of the file to stat. */ 00055 string filename; 00056 00057 /** The last time a stat() was performed. */ 00058 time_t last_time; 00059 00060 /** 00061 * Checks whether <em>interval</em> seconds have elapsed since <em>begin</em> 00062 * The current time is returned via the <tt>currentTime</tt> argument, 00063 * so that the caller doesn't have to call time() again if it needs the current 00064 * time. 00065 * 00066 * @pre begin <= time(NULL) 00067 * @return Whether <tt>interval</tt> seconds have elapsed since <tt>begin</tt>. 00068 * @throws SystemException Something went wrong while retrieving the time. 00069 * @throws boost::thread_interrupted 00070 */ 00071 bool expired(time_t begin, unsigned int interval, time_t ¤tTime) { 00072 currentTime = SystemTime::get(); 00073 return (unsigned int) (currentTime - begin) >= interval; 00074 } 00075 00076 public: 00077 /** The cached stat info. */ 00078 struct stat info; 00079 00080 /** 00081 * Creates a new CachedFileStat object. The file will not be 00082 * stat()ted until you call refresh(). 00083 * 00084 * @param filename The file to stat. 00085 */ 00086 CachedFileStat(const string &filename) { 00087 memset(&info, 0, sizeof(struct stat)); 00088 last_result = -1; 00089 last_errno = 0; 00090 this->filename = filename; 00091 last_time = 0; 00092 } 00093 00094 /** 00095 * Re-stat() the file, if necessary. If <tt>throttleRate</tt> seconds have 00096 * passed since the last time stat() was called, then the file will be 00097 * re-stat()ted. 00098 * 00099 * The stat information, which may either be the result of a new stat() call 00100 * or just the old cached information, is be available in the <tt>info</tt> 00101 * member. 00102 * 00103 * @return 0 if the stat() call succeeded or if no stat() was performed, 00104 * -1 if something went wrong while statting the file. In the latter 00105 * case, <tt>errno</tt> will be populated with an appropriate error code. 00106 * @throws SystemException Something went wrong while retrieving the 00107 * system time. stat() errors will <em>not</em> result in SystemException 00108 * being thrown. 00109 * @throws boost::thread_interrupted 00110 */ 00111 int refresh(unsigned int throttleRate) { 00112 time_t currentTime; 00113 00114 if (expired(last_time, throttleRate, currentTime)) { 00115 last_result = syscalls::stat(filename.c_str(), &info); 00116 last_errno = errno; 00117 last_time = currentTime; 00118 return last_result; 00119 } else { 00120 errno = last_errno; 00121 return last_result; 00122 } 00123 } 00124 }; 00125 00126 } // namespace Passenger 00127 00128 #endif /* __cplusplus */ 00129 00130 00131 #ifdef __cplusplus 00132 extern "C" { 00133 #endif 00134 00135 /** 00136 * CachedMultiFileStat allows one to stat() files at a throttled rate, in order 00137 * to minimize stress on the filesystem. It does this by caching the old stat 00138 * data for a specified amount of time. 00139 * 00140 * Unlike CachedFileStat, which can only stat() one specific file per 00141 * CachedFileStat object, CachedMultiFileStat can stat() any file. The 00142 * number of cached stat() information is limited by the given cache size. 00143 * 00144 * This class is fully thread-safe. 00145 */ 00146 typedef struct CachedMultiFileStat CachedMultiFileStat; 00147 00148 CachedMultiFileStat *cached_multi_file_stat_new(unsigned int max_size); 00149 void cached_multi_file_stat_free(CachedMultiFileStat *mstat); 00150 int cached_multi_file_stat_perform(CachedMultiFileStat *mstat, 00151 const char *filename, 00152 struct stat *buf, 00153 unsigned int throttle_rate); 00154 00155 #ifdef __cplusplus 00156 } 00157 #endif 00158 00159 #endif /* _PASSENGER_CACHED_FILE_STAT_H_ */ 00160