Write the depslog version in binary instead of text.
[platform/upstream/ninja.git] / src / deps_log.cc
1 // Copyright 2012 Google Inc. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "deps_log.h"
16
17 #include <assert.h>
18 #include <stdio.h>
19 #include <errno.h>
20 #include <string.h>
21 #include <unistd.h>
22
23 #include "graph.h"
24 #include "metrics.h"
25 #include "state.h"
26 #include "util.h"
27
28 // The version is stored as 4 bytes after the signature and also serves as a
29 // byte order mark. Signature and version combined are 16 bytes long.
30 const char kFileSignature[] = "# ninjadeps\n";
31 const int kCurrentVersion = 1;
32
33 DepsLog::~DepsLog() {
34   Close();
35 }
36
37 bool DepsLog::OpenForWrite(const string& path, string* err) {
38   file_ = fopen(path.c_str(), "ab");
39   if (!file_) {
40     *err = strerror(errno);
41     return false;
42   }
43   SetCloseOnExec(fileno(file_));
44
45   // Opening a file in append mode doesn't set the file pointer to the file's
46   // end on Windows. Do that explicitly.
47   fseek(file_, 0, SEEK_END);
48
49   if (ftell(file_) == 0) {
50     if (fwrite(kFileSignature, sizeof(kFileSignature) - 1, 1, file_) < 1) {
51       *err = strerror(errno);
52       return false;
53     }
54     if (fwrite(&kCurrentVersion, 4, 1, file_) < 1) {
55       *err = strerror(errno);
56       return false;
57     }
58   }
59
60   return true;
61 }
62
63 bool DepsLog::RecordDeps(Node* node, TimeStamp mtime,
64                          const vector<Node*>& nodes) {
65   return RecordDeps(node, mtime, nodes.size(),
66                     nodes.empty() ? NULL : (Node**)&nodes.front());
67 }
68
69 bool DepsLog::RecordDeps(Node* node, TimeStamp mtime,
70                          int node_count, Node** nodes) {
71   // Track whether there's any new data to be recorded.
72   bool made_change = false;
73
74   // Assign ids to all nodes that are missing one.
75   if (node->id() < 0) {
76     RecordId(node);
77     made_change = true;
78   }
79   for (int i = 0; i < node_count; ++i) {
80     if (nodes[i]->id() < 0) {
81       RecordId(nodes[i]);
82       made_change = true;
83     }
84   }
85
86   // See if the new data is different than the existing data, if any.
87   if (!made_change) {
88     Deps* deps = GetDeps(node);
89     if (!deps ||
90         deps->mtime != mtime ||
91         deps->node_count != node_count) {
92       made_change = true;
93     } else {
94       for (int i = 0; i < node_count; ++i) {
95         if (deps->nodes[i] != nodes[i]) {
96           made_change = true;
97           break;
98         }
99       }
100     }
101   }
102
103   // Don't write anything if there's no new info.
104   if (!made_change)
105     return true;
106
107   uint16_t size = 4 * (1 + 1 + (uint16_t)node_count);
108   size |= 0x8000;  // Deps record: set high bit.
109   fwrite(&size, 2, 1, file_);
110   int id = node->id();
111   fwrite(&id, 4, 1, file_);
112   int timestamp = mtime;
113   fwrite(&timestamp, 4, 1, file_);
114   for (int i = 0; i < node_count; ++i) {
115     id = nodes[i]->id();
116     fwrite(&id, 4, 1, file_);
117   }
118
119   return true;
120 }
121
122 void DepsLog::Close() {
123   if (file_)
124     fclose(file_);
125   file_ = NULL;
126 }
127
128 bool DepsLog::Load(const string& path, State* state, string* err) {
129   METRIC_RECORD(".ninja_deps load");
130   char buf[32 << 10];
131   FILE* f = fopen(path.c_str(), "rb");
132   if (!f) {
133     if (errno == ENOENT)
134       return true;
135     *err = strerror(errno);
136     return false;
137   }
138
139   if (!fgets(buf, sizeof(buf), f)) {
140     *err = strerror(errno);
141     return false;
142   }
143   int version = 0;
144   if (fread(&version, 4, 1, f) < 1) {
145     *err = strerror(errno);
146     return false;
147   }
148   if (version != kCurrentVersion) {
149     *err = "bad deps log signature or version; starting over";
150     fclose(f);
151     unlink(path.c_str());
152     // Don't report this as a failure.  An empty deps log will cause
153     // us to rebuild the outputs anyway.
154     return true;
155   }
156
157   for (;;) {
158     uint16_t size;
159     if (fread(&size, 2, 1, f) < 1)
160       break;
161     bool is_deps = (size >> 15) != 0;
162     size = size & 0x7FFF;
163
164     if (fread(buf, size, 1, f) < 1)
165       break;
166
167     if (is_deps) {
168       assert(size % 4 == 0);
169       int* deps_data = reinterpret_cast<int*>(buf);
170       int out_id = deps_data[0];
171       int mtime = deps_data[1];
172       deps_data += 2;
173       int deps_count = (size / 4) - 2;
174
175       Deps* deps = new Deps;
176       deps->mtime = mtime;
177       deps->node_count = deps_count;
178       deps->nodes = new Node*[deps_count];
179       for (int i = 0; i < deps_count; ++i) {
180         assert(deps_data[i] < (int)nodes_.size());
181         assert(nodes_[deps_data[i]]);
182         deps->nodes[i] = nodes_[deps_data[i]];
183       }
184
185       if (out_id >= (int)deps_.size())
186         deps_.resize(out_id + 1);
187       if (deps_[out_id]) {
188         ++dead_record_count_;
189         delete deps_[out_id];
190       }
191       deps_[out_id] = deps;
192     } else {
193       StringPiece path(buf, size);
194       Node* node = state->GetNode(path);
195       assert(node->id() < 0);
196       node->set_id(nodes_.size());
197       nodes_.push_back(node);
198     }
199   }
200   if (ferror(f)) {
201     *err = strerror(ferror(f));
202     return false;
203   }
204   fclose(f);
205   return true;
206 }
207
208 DepsLog::Deps* DepsLog::GetDeps(Node* node) {
209   if (node->id() < 0)
210     return NULL;
211   return deps_[node->id()];
212 }
213
214 bool DepsLog::Recompact(const string& path, string* err) {
215   METRIC_RECORD(".ninja_deps recompact");
216   printf("Recompacting deps...\n");
217
218   string temp_path = path + ".recompact";
219   DepsLog new_log;
220   if (!new_log.OpenForWrite(temp_path, err))
221     return false;
222
223   // Clear all known ids so that new ones can be reassigned.
224   for (vector<Node*>::iterator i = nodes_.begin();
225        i != nodes_.end(); ++i) {
226     (*i)->set_id(-1);
227   }
228
229   // Write out all deps again.
230   for (int old_id = 0; old_id < (int)deps_.size(); ++old_id) {
231     Deps* deps = deps_[old_id];
232     if (!new_log.RecordDeps(nodes_[old_id], deps->mtime,
233                             deps->node_count, deps->nodes)) {
234       new_log.Close();
235       return false;
236     }
237   }
238
239   new_log.Close();
240
241   if (unlink(path.c_str()) < 0) {
242     *err = strerror(errno);
243     return false;
244   }
245
246   if (rename(temp_path.c_str(), path.c_str()) < 0) {
247     *err = strerror(errno);
248     return false;
249   }
250
251   return true;
252 }
253
254 bool DepsLog::RecordId(Node* node) {
255   uint16_t size = (uint16_t)node->path().size();
256   fwrite(&size, 2, 1, file_);
257   fwrite(node->path().data(), node->path().size(), 1, file_);
258
259   node->set_id(nodes_.size());
260   nodes_.push_back(node);
261
262   return true;
263 }