18 #ifndef __STDC_FORMAT_MACROS 19 #define __STDC_FORMAT_MACROS 40 #if defined(_MSC_VER) && (_MSC_VER < 1800) 41 #define strtoll _strtoi64 56 const int kOldestSupportedVersion = 4;
61 #define BIG_CONSTANT(x) (x) 62 #else // defined(_MSC_VER) 63 #define BIG_CONSTANT(x) (x##LLU) 64 #endif // !defined(_MSC_VER) 66 uint64_t MurmurHash64A(
const void* key,
size_t len) {
67 static const uint64_t seed = 0xDECAFBADDECAFBADull;
71 const unsigned char* data = (
const unsigned char*)key;
74 memcpy(&k, data,
sizeof k);
85 case 7: h ^=
uint64_t(data[6]) << 48;
87 case 6: h ^=
uint64_t(data[5]) << 40;
89 case 5: h ^=
uint64_t(data[4]) << 32;
91 case 4: h ^=
uint64_t(data[3]) << 24;
93 case 3: h ^=
uint64_t(data[2]) << 16;
112 return MurmurHash64A(command.
str_, command.
len_);
119 int start_time,
int end_time,
TimeStamp restat_mtime)
120 : output(output), command_hash(command_hash),
121 start_time(start_time), end_time(end_time), mtime(restat_mtime)
148 for (vector<Node*>::iterator out = edge->
outputs_.begin();
149 out != edge->
outputs_.end(); ++out) {
150 const string& path = (*out)->path();
151 Entries::iterator i =
entries_.find(path);
154 log_entry = i->second;
157 entries_.insert(Entries::value_type(log_entry->
output, log_entry));
162 log_entry->
mtime = mtime;
193 if (setvbuf(
log_file_, NULL, _IOLBF, BUFSIZ) != 0) {
220 bool ReadLine(
char** line_start,
char** line_end) {
237 size_t size_rest = (
buf_end_ -
buf_) - already_consumed;
240 size_t read = fread(
buf_ + size_rest, 1,
sizeof(
buf_) - size_rest,
file_);
263 FILE* file = fopen(path.c_str(),
"r");
267 *err = strerror(errno);
272 int unique_entry_count = 0;
273 int total_entry_count = 0;
276 char* line_start = 0;
278 while (reader.
ReadLine(&line_start, &line_end)) {
282 if (log_version < kOldestSupportedVersion) {
283 *err = (
"build log version invalid, perhaps due to being too old; " 286 unlink(path.c_str());
297 const char kFieldSeparator =
'\t';
299 char* start = line_start;
300 char* end = (
char*)memchr(start, kFieldSeparator, line_end - start);
305 int start_time = 0, end_time = 0;
308 start_time = atoi(start);
311 end = (
char*)memchr(start, kFieldSeparator, line_end - start);
315 end_time = atoi(start);
318 end = (
char*)memchr(start, kFieldSeparator, line_end - start);
322 restat_mtime = strtoll(start, NULL, 10);
325 end = (
char*)memchr(start, kFieldSeparator, line_end - start);
328 string output = string(start, end - start);
334 Entries::iterator i =
entries_.find(output);
340 ++unique_entry_count;
346 entry->
mtime = restat_mtime;
347 if (log_version >= 5) {
348 char c = *end; *end =
'\0';
365 int kMinCompactionEntryCount = 100;
366 int kCompactionRatio = 3;
369 }
else if (total_entry_count > kMinCompactionEntryCount &&
370 total_entry_count > unique_entry_count * kCompactionRatio) {
378 Entries::iterator i =
entries_.find(path);
385 return fprintf(f,
"%d\t%d\t%" PRId64 "\t%s\t%" PRIx64 "\n",
395 string temp_path = path +
".recompact";
396 FILE* f = fopen(temp_path.c_str(),
"wb");
398 *err = strerror(errno);
403 *err = strerror(errno);
408 vector<StringPiece> dead_outputs;
411 dead_outputs.push_back(i->first);
416 *err = strerror(errno);
422 for (
size_t i = 0; i < dead_outputs.size(); ++i)
426 if (unlink(path.c_str()) < 0) {
427 *err = strerror(errno);
431 if (rename(temp_path.c_str(), path.c_str()) < 0) {
432 *err = strerror(errno);
441 const int output_count,
char** outputs,
442 std::string*
const err) {
446 std::string temp_path = path.
AsString() +
".restat";
447 FILE* f = fopen(temp_path.c_str(),
"wb");
449 *err = strerror(errno);
454 *err = strerror(errno);
459 bool skip = output_count > 0;
460 for (
int j = 0; j < output_count; ++j) {
461 if (i->second->output == outputs[j]) {
467 const TimeStamp mtime = disk_interface.
Stat(i->second->output, err);
472 i->second->mtime = mtime;
476 *err = strerror(errno);
483 if (unlink(path.
str_) < 0) {
484 *err = strerror(errno);
488 if (rename(temp_path.c_str(), path.
str_) < 0) {
489 *err = strerror(errno);
bool OpenForWrite(const std::string &path, const BuildLogUser &user, std::string *err)
Prepares writing to the log file without actually opening it - that will happen when/if it's needed...
bool Recompact(const std::string &path, const BuildLogUser &user, std::string *err)
Rewrite the known log entries, throwing away old data.
const int kCurrentVersion
std::string AsString() const
Convert the slice into a full-fledged std::string, copying the data into a new string.
LoadStatus Load(const std::string &path, std::string *err)
Load the on-disk log.
const char kFileSignature[]
bool RecordCommand(Edge *edge, int start_time, int end_time, TimeStamp mtime=0)
bool Restat(StringPiece path, const DiskInterface &disk_interface, int output_count, char **outputs, std::string *err)
Restat all outputs in the log.
StringPiece represents a slice of a string whose memory is managed externally.
bool WriteEntry(FILE *f, const LogEntry &entry)
Serialize an entry into a log file.
Interface for accessing the disk.
std::vector< Node * > outputs_
An edge in the dependency graph; links between Nodes using Rules.
virtual bool IsPathDead(StringPiece s) const =0
Return if a given output is no longer part of the build manifest.
void SetCloseOnExec(int fd)
Mark a file descriptor to not be inherited on exec()s.
bool OpenForWriteIfNeeded()
Should be called before using log_file_.
#define NINJA_FALLTHROUGH
#define METRIC_RECORD(name)
The primary interface to metrics.
std::string log_file_path_
static uint64_t HashCommand(StringPiece command)
std::string EvaluateCommand(bool incl_rsp_file=false) const
Expand all variables in a command and return it as a string.
LogEntry * LookupByOutput(const std::string &path)
Lookup a previously-run command by its output path.
unsigned long long uint64_t
LogEntry(const std::string &output)
virtual TimeStamp Stat(const std::string &path, std::string *err) const =0
stat() a file, returning the mtime, or 0 if missing and -1 on other errors.
bool ReadLine(char **line_start, char **line_end)
Can answer questions about the manifest for the BuildLog.