v1.18: address bad pp.dep caches?

This commit is contained in:
David Rose 2004-10-25 20:47:38 +00:00
parent f68ab23323
commit cfe15fb80b
5 changed files with 176 additions and 56 deletions

View File

@ -86,5 +86,5 @@
** Also be sure to change the version number ** ** Also be sure to change the version number **
** at the beginning of configure.in. ** ** at the beginning of configure.in. **
**************** ****************/ **************** ****************/
#define VERSION "1.17" #define VERSION "1.18"
/**************** UPDATE VERSION NUMBER HERE ****************/ /**************** UPDATE VERSION NUMBER HERE ****************/

View File

@ -5,7 +5,7 @@ dnl **************** UPDATE VERSION NUMBER HERE ****************
dnl ** Also be sure to change the version number ** dnl ** Also be sure to change the version number **
dnl ** at the end of config_msvc.h. ** dnl ** at the end of config_msvc.h. **
dnl **************** **************** dnl **************** ****************
AM_INIT_AUTOMAKE(ppremake, 1.17) AM_INIT_AUTOMAKE(ppremake, 1.18)
dnl **************** UPDATE VERSION NUMBER HERE **************** dnl **************** UPDATE VERSION NUMBER HERE ****************
AM_CONFIG_HEADER(config.h) AM_CONFIG_HEADER(config.h)

View File

@ -60,8 +60,11 @@ PPDependableFile(PPDirectory *directory, const string &filename) :
// cached modification time against the file's actual // cached modification time against the file's actual
// modification time, and storing the cached // modification time, and storing the cached
// dependencies if they match. // dependencies if they match.
//
// The return value is true if the cache is valid, false
// if something appears to be wrong.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
void PPDependableFile:: bool PPDependableFile::
update_from_cache(const vector<string> &words) { update_from_cache(const vector<string> &words) {
// Shouldn't call this once the file has actually been read. // Shouldn't call this once the file has actually been read.
assert((_flags & F_updated) == 0); assert((_flags & F_updated) == 0);
@ -69,44 +72,63 @@ update_from_cache(const vector<string> &words) {
assert((_flags & F_from_cache) == 0); assert((_flags & F_from_cache) == 0);
assert(words.size() >= 2); assert(words.size() >= 2);
// The second parameter is the cached modification time. if (!exists()) {
time_t mtime = strtol(words[1].c_str(), (char **)NULL, 10); // The file doesn't even exist; clearly the cache is bad.
if (mtime == get_mtime()) { _flags |= F_bad_cache;
// The modification matches; preserve the cache information.
PPDirectoryTree *tree = _directory->get_tree();
_dependencies.clear(); } else {
vector<string>::const_iterator wi; // The second parameter is the cached modification time.
for (wi = words.begin() + 2; wi != words.end(); ++wi) { time_t mtime = strtol(words[1].c_str(), (char **)NULL, 10);
string dirpath = (*wi); if (mtime == get_mtime()) {
// The modification matches; preserve the cache information.
PPDirectoryTree *tree = _directory->get_tree();
Dependency dep; _dependencies.clear();
dep._okcircular = false; vector<string>::const_iterator wi;
for (wi = words.begin() + 2; wi != words.end(); ++wi) {
string dirpath = (*wi);
if (dirpath.length() > 1 && dirpath[0] == '/') { Dependency dep;
// If the first character is '/', it means that the file has dep._okcircular = false;
// been marked okcircular.
dep._okcircular = true;
dirpath = dirpath.substr(1);
}
if (dirpath.length() > 2 && dirpath.substr(0, 2) == "*/") { if (dirpath.length() > 1 && dirpath[0] == '/') {
// This is an extra include file, not a file in this source // If the first character is '/', it means that the file has
// tree. // been marked okcircular.
_extra_includes.push_back(dirpath.substr(2)); dep._okcircular = true;
dirpath = dirpath.substr(1);
}
} else { if (dirpath.length() > 2 && dirpath.substr(0, 2) == "*/") {
dep._file = // This is an extra include file, not a file in this source
tree->get_dependable_file_by_dirpath(dirpath, false); // tree.
if (dep._file != (PPDependableFile *)NULL) { _extra_includes.push_back(dirpath.substr(2));
_dependencies.push_back(dep);
} else {
dep._file =
tree->get_dependable_file_by_dirpath(dirpath, false);
if (dep._file != (PPDependableFile *)NULL) {
_dependencies.push_back(dep);
}
} }
} }
}
_flags |= F_from_cache; _flags |= F_from_cache;
sort(_dependencies.begin(), _dependencies.end()); sort(_dependencies.begin(), _dependencies.end());
}
} }
return ((_flags & F_bad_cache) == 0);
}
////////////////////////////////////////////////////////////////////
// Function: PPDependableFile::clear_cache
// Access: Public
// Description: Forgets the cache we just read.
////////////////////////////////////////////////////////////////////
void PPDependableFile::
clear_cache() {
_dependencies.clear();
_flags &= ~(F_bad_cache | F_from_cache);
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -317,6 +339,17 @@ was_examined() const {
return ((_flags & F_updated) != 0); return ((_flags & F_updated) != 0);
} }
////////////////////////////////////////////////////////////////////
// Function: PPDependableFile::was_cached
// Access: Public
// Description: Returns true if this file was found in the cache,
// false otherwise.
////////////////////////////////////////////////////////////////////
bool PPDependableFile::
was_cached() const {
return ((_flags & F_from_cache) != 0);
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: PPDependableFile::update_dependencies // Function: PPDependableFile::update_dependencies
// Access: Private // Access: Private
@ -375,6 +408,7 @@ compute_dependencies(string &circularity) {
} else { } else {
cerr << "Warning: dependent file " << filename cerr << "Warning: dependent file " << filename
<< " does not exist.\n"; << " does not exist.\n";
_flags |= F_bad_cache;
} }
} else { } else {
@ -427,6 +461,12 @@ compute_dependencies(string &circularity) {
// with an "okcircular" comment. // with an "okcircular" comment.
if (!(*di)._okcircular) { if (!(*di)._okcircular) {
circ = (*di)._file->compute_dependencies(circularity); circ = (*di)._file->compute_dependencies(circularity);
if (((*di)._file->_flags & F_bad_cache) != 0) {
// If our dependent file had a broken cache, our own cache is
// suspect.
_flags |= F_bad_cache;
}
if (circ != (PPDependableFile *)NULL) { if (circ != (PPDependableFile *)NULL) {
// Oops, a circularity. Silly user. // Oops, a circularity. Silly user.
circularity = get_dirpath() + " => " + circularity; circularity = get_dirpath() + " => " + circularity;
@ -441,6 +481,19 @@ compute_dependencies(string &circularity) {
_flags = (_flags & ~F_updating) | F_updated; _flags = (_flags & ~F_updating) | F_updated;
sort(_dependencies.begin(), _dependencies.end()); sort(_dependencies.begin(), _dependencies.end());
if ((_flags & (F_bad_cache | F_from_cache)) == (F_bad_cache | F_from_cache)) {
// Our cache is suspect. Re-read the file to flush the cache.
if (verbose || true) {
cerr << "Dependency cache for \"" << get_fullpath() << "\" is suspect.\n";
}
clear_cache();
_flags &= ~F_updated;
return compute_dependencies(circularity);
}
return circ; return circ;
} }

View File

@ -29,7 +29,8 @@ class PPDirectory;
class PPDependableFile { class PPDependableFile {
public: public:
PPDependableFile(PPDirectory *directory, const string &filename); PPDependableFile(PPDirectory *directory, const string &filename);
void update_from_cache(const vector<string> &words); bool update_from_cache(const vector<string> &words);
void clear_cache();
void write_cache(ostream &out); void write_cache(ostream &out);
PPDirectory *get_directory() const; PPDirectory *get_directory() const;
@ -51,6 +52,7 @@ public:
string get_circularity(); string get_circularity();
bool was_examined() const; bool was_examined() const;
bool was_cached() const;
private: private:
void update_dependencies(); void update_dependencies();
@ -67,6 +69,7 @@ private:
F_statted = 0x008, F_statted = 0x008,
F_exists = 0x010, F_exists = 0x010,
F_from_cache = 0x020, F_from_cache = 0x020,
F_bad_cache = 0x040,
}; };
int _flags; int _flags;
string _circularity; string _circularity;

View File

@ -23,6 +23,8 @@
#include <sys/types.h> #include <sys/types.h>
#endif #endif
#include <sys/stat.h>
#include <algorithm> #include <algorithm>
#include <assert.h> #include <assert.h>
@ -31,6 +33,9 @@
#include <windows.h> #include <windows.h>
#endif #endif
// How new must a pp.dep cache file be before we will believe it?
static const int max_cache_minutes = 60;
PPDirectory *current_output_directory = (PPDirectory *)NULL; PPDirectory *current_output_directory = (PPDirectory *)NULL;
// An STL object to sort directories in order by dependency and then // An STL object to sort directories in order by dependency and then
@ -715,26 +720,86 @@ read_file_dependencies(const string &cache_filename) {
cache_pathname.set_text(); cache_pathname.set_text();
ifstream in; ifstream in;
if (!cache_pathname.open_read(in)) { // Does the cache file exist, and is it recent enough? We don't
// Can't read it. Maybe it's not there. No problem. // trust old cache files on principle.
string os_specific = cache_pathname.to_os_specific();
time_t now = time(NULL);
#ifdef WIN32_VC
struct _stat this_buf;
bool this_exists = false;
if (_stat(os_specific.c_str(), &this_buf) == 0) {
this_exists = true;
}
#else // WIN32_VC
struct stat this_buf;
bool this_exists = false;
if (stat(os_specific.c_str(), &this_buf) == 0) {
this_exists = true;
}
#endif
if (!this_exists) {
// The cache file doesn't exist. That's OK.
if (verbose) { if (verbose) {
cerr << "Couldn't read \"" << cache_pathname << "\"\n"; cerr << "No cache file: \"" << cache_pathname << "\"\n";
}
} else {
if (verbose) {
cerr << "Loading cache \"" << cache_pathname << "\"\n";
} }
string line; } else if (this_buf.st_mtime < now - 60 * max_cache_minutes) {
getline(in, line); // It exists, but it's too old.
while (!in.fail() && !in.eof()) { if (verbose) {
vector<string> words; cerr << "Cache file too old: \"" << cache_pathname << "\"\n";
tokenize_whitespace(line, words); }
if (words.size() >= 2) {
PPDependableFile *file = get_dependable_file(words[0], false); } else {
file->update_from_cache(words); // It exists and is new enough; use it.
if (!cache_pathname.open_read(in)) {
cerr << "Couldn't read \"" << cache_pathname << "\"\n";
} else {
if (verbose) {
cerr << "Loading cache \"" << cache_pathname << "\"\n";
} }
bool okcache = true;
string line;
getline(in, line); getline(in, line);
while (!in.fail() && !in.eof()) {
vector<string> words;
tokenize_whitespace(line, words);
if (words.size() >= 2) {
PPDependableFile *file = get_dependable_file(words[0], false);
if (!file->update_from_cache(words)) {
// Hey, we asked for an invalid or absent file. Phooey.
// Invalidate the cache, and also make sure that this
// particular file (which maybe doesn't even exist) isn't
// mentioned in the cache file any more.
Dependables::iterator di;
di = _dependables.find(words[0]);
if (di != _dependables.end()) {
_dependables.erase(di);
}
okcache = false;
break;
}
}
getline(in, line);
}
if (!okcache) {
if (verbose || true) {
cerr << "Cache \"" << cache_pathname << "\" is stale.\n";
}
Dependables::iterator di;
for (di = _dependables.begin(); di != _dependables.end(); ++di) {
(*di).second->clear_cache();
}
}
} }
} }
@ -773,9 +838,8 @@ update_file_dependencies(const string &cache_filename) {
cache_pathname.unlink(); cache_pathname.unlink();
// If we have no files, don't bother writing the cache. // If we have no files, don't bother writing the cache.
bool wrote_anything = false;
if (!_dependables.empty()) { if (!_dependables.empty()) {
bool wrote_anything = false;
ofstream out; ofstream out;
if (!cache_pathname.open_write(out)) { if (!cache_pathname.open_write(out)) {
cerr << "Cannot update cache dependency file " << cache_pathname << "\n"; cerr << "Cannot update cache dependency file " << cache_pathname << "\n";
@ -792,7 +856,7 @@ update_file_dependencies(const string &cache_filename) {
Dependables::const_iterator di; Dependables::const_iterator di;
for (di = _dependables.begin(); di != _dependables.end(); ++di) { for (di = _dependables.begin(); di != _dependables.end(); ++di) {
PPDependableFile *file = (*di).second; PPDependableFile *file = (*di).second;
if (file->was_examined() || external_tree) { if (file->was_examined() || (external_tree && file->was_cached())) {
if (file->is_circularity()) { if (file->is_circularity()) {
cerr << "Warning: circular #include directives:\n" cerr << "Warning: circular #include directives:\n"
<< " " << file->get_circularity() << "\n"; << " " << file->get_circularity() << "\n";
@ -803,12 +867,12 @@ update_file_dependencies(const string &cache_filename) {
} }
out.close(); out.close();
}
if (!wrote_anything) { if (!wrote_anything) {
// Well, if we didn't write anything, remove the cache file // Well, if we didn't write anything, remove the cache file
// after all. // after all.
cache_pathname.unlink(); cache_pathname.unlink();
}
} }
} }