22 #define __STDC_FORMAT_MACROS 42 const int kOldestSupportedVersion = 4;
47 #define BIG_CONSTANT(x) (x) 48 #else // defined(_MSC_VER) 49 #define BIG_CONSTANT(x) (x##LLU) 50 #endif // !defined(_MSC_VER) 52 uint64_t MurmurHash64A(
const void* key,
size_t len) {
53 static const uint64_t seed = 0xDECAFBADDECAFBADull;
57 const unsigned char* data = (
const unsigned char*)key;
60 memcpy(&k, data,
sizeof k);
71 case 7: h ^=
uint64_t(data[6]) << 48;
72 case 6: h ^=
uint64_t(data[5]) << 40;
73 case 5: h ^=
uint64_t(data[4]) << 32;
74 case 4: h ^=
uint64_t(data[3]) << 24;
75 case 3: h ^=
uint64_t(data[2]) << 16;
92 return MurmurHash64A(command.
str_, command.
len_);
100 : output(output), command_hash(command_hash),
101 start_time(start_time), end_time(end_time), restat_mtime(restat_mtime)
120 *err = strerror(errno);
123 setvbuf(
log_file_, NULL, _IOLBF, BUFSIZ);
132 *err = strerror(errno);
144 for (vector<Node*>::iterator out = edge->
outputs_.begin();
145 out != edge->
outputs_.end(); ++out) {
146 const string& path = (*out)->path();
147 Entries::iterator i =
entries_.find(path);
150 log_entry = i->second;
153 entries_.insert(Entries::value_type(log_entry->
output, log_entry));
176 : file_(file), buf_end_(buf_), line_start_(buf_), line_end_(NULL) {
177 memset(buf_, 0,
sizeof(buf_));
184 bool ReadLine(
char** line_start,
char** line_end) {
185 if (line_start_ >= buf_end_ || !line_end_) {
187 size_t size_read = fread(buf_, 1,
sizeof(buf_), file_);
191 buf_end_ = buf_ + size_read;
194 line_start_ = line_end_ + 1;
197 line_end_ = (
char*)memchr(line_start_,
'\n', buf_end_ - line_start_);
200 size_t already_consumed = line_start_ - buf_;
201 size_t size_rest = (buf_end_ - buf_) - already_consumed;
202 memmove(buf_, line_start_, size_rest);
204 size_t read = fread(buf_ + size_rest, 1,
sizeof(buf_) - size_rest, file_);
205 buf_end_ = buf_ + size_rest + read;
207 line_end_ = (
char*)memchr(line_start_,
'\n', buf_end_ - line_start_);
210 *line_start = line_start_;
211 *line_end = line_end_;
217 char buf_[256 << 10];
227 FILE* file = fopen(path.c_str(),
"r");
231 *err = strerror(errno);
236 int unique_entry_count = 0;
237 int total_entry_count = 0;
240 char* line_start = 0;
242 while (reader.
ReadLine(&line_start, &line_end)) {
246 if (log_version < kOldestSupportedVersion) {
247 *err = (
"build log version invalid, perhaps due to being too old; " 250 unlink(path.c_str());
261 const char kFieldSeparator =
'\t';
263 char* start = line_start;
264 char* end = (
char*)memchr(start, kFieldSeparator, line_end - start);
269 int start_time = 0, end_time = 0;
272 start_time = atoi(start);
275 end = (
char*)memchr(start, kFieldSeparator, line_end - start);
279 end_time = atoi(start);
282 end = (
char*)memchr(start, kFieldSeparator, line_end - start);
286 restat_mtime = atol(start);
289 end = (
char*)memchr(start, kFieldSeparator, line_end - start);
292 string output = string(start, end - start);
298 Entries::iterator i =
entries_.find(output);
304 ++unique_entry_count;
311 if (log_version >= 5) {
312 char c = *end; *end =
'\0';
329 int kMinCompactionEntryCount = 100;
330 int kCompactionRatio = 3;
333 }
else if (total_entry_count > kMinCompactionEntryCount &&
334 total_entry_count > unique_entry_count * kCompactionRatio) {
342 Entries::iterator i =
entries_.find(path);
349 return fprintf(f,
"%d\t%d\t%d\t%s\t%" PRIx64 "\n",
357 printf(
"Recompacting log...\n");
360 string temp_path = path +
".recompact";
361 FILE* f = fopen(temp_path.c_str(),
"wb");
363 *err = strerror(errno);
368 *err = strerror(errno);
373 vector<StringPiece> dead_outputs;
376 dead_outputs.push_back(i->first);
381 *err = strerror(errno);
387 for (
size_t i = 0; i < dead_outputs.size(); ++i)
391 if (unlink(path.c_str()) < 0) {
392 *err = strerror(errno);
396 if (rename(temp_path.c_str(), path.c_str()) < 0) {
397 *err = strerror(errno);
const int kCurrentVersion
const char kFileSignature[]
bool Recompact(const string &path, const BuildLogUser &user, string *err)
Rewrite the known log entries, throwing away old data.
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.
An edge in the dependency graph; links between Nodes using Rules.
string EvaluateCommand(bool incl_rsp_file=false)
Expand all variables in a command and return it as a string.
virtual bool IsPathDead(StringPiece s) const =0
Return if a given output no longer part of the build manifest.
void SetCloseOnExec(int fd)
Mark a file descriptor to not be inherited on exec()s.
bool OpenForWrite(const string &path, const BuildLogUser &user, string *err)
LogEntry(const string &output)
#define METRIC_RECORD(name)
The primary interface to metrics.
static uint64_t HashCommand(StringPiece command)
LogEntry * LookupByOutput(const string &path)
Lookup a previously-run command by its output path.
bool RecordCommand(Edge *edge, int start_time, int end_time, TimeStamp restat_mtime=0)
unsigned long long uint64_t
bool Load(const string &path, string *err)
Load the on-disk log.
bool ReadLine(char **line_start, char **line_end)
Can answer questions about the manifest for the BuildLog.
vector< Node * > outputs_