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 system time. 00107 * @throws boost::thread_interrupted 00108 */ 00109 int refresh(unsigned int throttleRate) { 00110 time_t currentTime; 00111 int ret; 00112 00113 if (expired(last_time, throttleRate, currentTime)) { 00114 ret = stat(filename.c_str(), &info); 00115 if (ret == -1 && errno == EINTR) { 00116 /* If the stat() call was interrupted, then don't 00117 * update any state so that the caller can call 00118 * this function again without us returning a 00119 * cached EINTR error. 00120 */ 00121 return -1; 00122 } else { 00123 last_result = ret; 00124 last_errno = errno; 00125 last_time = currentTime; 00126 return ret; 00127 } 00128 } else { 00129 errno = last_errno; 00130 return last_result; 00131 } 00132 } 00133 }; 00134 00135 } // namespace Passenger 00136 00137 #endif /* __cplusplus */ 00138 00139 00140 #ifdef __cplusplus 00141 extern "C" { 00142 #endif 00143 00144 /** 00145 * CachedMultiFileStat allows one to stat() files at a throttled rate, in order 00146 * to minimize stress on the filesystem. It does this by caching the old stat 00147 * data for a specified amount of time. 00148 * 00149 * Unlike CachedFileStat, which can only stat() one specific file per 00150 * CachedFileStat object, CachedMultiFileStat can stat() any file. The 00151 * number of cached stat() information is limited by the given cache size. 00152 * 00153 * This class is fully thread-safe. 00154 */ 00155 typedef struct CachedMultiFileStat CachedMultiFileStat; 00156 00157 CachedMultiFileStat *cached_multi_file_stat_new(unsigned int max_size); 00158 void cached_multi_file_stat_free(CachedMultiFileStat *mstat); 00159 int cached_multi_file_stat_perform(CachedMultiFileStat *mstat, 00160 const char *filename, 00161 struct stat *buf, 00162 unsigned int throttle_rate); 00163 00164 #ifdef __cplusplus 00165 } 00166 #endif 00167 00168 #endif /* _PASSENGER_CACHED_FILE_STAT_H_ */ 00169