don't write out deps entries if nothing changed
authorEvan Martin <martine@danga.com>
Mon, 7 Jan 2013 18:59:27 +0000 (10:59 -0800)
committerEvan Martin <martine@danga.com>
Mon, 8 Apr 2013 22:01:36 +0000 (15:01 -0700)
Shortcuts a common case.

src/deps_log.cc
src/deps_log_test.cc

index da6cd93..0f10b5c 100644 (file)
@@ -50,15 +50,43 @@ bool DepsLog::OpenForWrite(const string& path, string* err) {
 
 bool DepsLog::RecordDeps(Node* node, TimeStamp mtime,
                          const vector<Node*>& nodes) {
+  // Track whether there's any new data to be recorded.
+  bool made_change = false;
+
   // Assign ids to all nodes that are missing one.
-  if (node->id() < 0)
+  if (node->id() < 0) {
     RecordId(node);
+    made_change = true;
+  }
   for (vector<Node*>::const_iterator i = nodes.begin();
        i != nodes.end(); ++i) {
-    if ((*i)->id() < 0)
+    if ((*i)->id() < 0) {
       RecordId(*i);
+      made_change = true;
+    }
+  }
+
+  // See if the new data is different than the existing data, if any.
+  if (!made_change) {
+    Deps* deps = GetDeps(node);
+    if (!deps ||
+        deps->mtime != mtime ||
+        deps->node_count != (int)nodes.size()) {
+      made_change = true;
+    } else {
+      for (int i = 0; i < (int)nodes.size(); ++i) {
+        if (deps->nodes[i] != nodes[i]) {
+          made_change = true;
+          break;
+        }
+      }
+    }
   }
 
+  // Don't write anything if there's no new info.
+  if (!made_change)
+    return true;
+
   uint16_t size = 4 * (1 + 1 + (uint16_t)nodes.size());
   size |= 0x8000;  // Deps record: set high bit.
   fwrite(&size, 2, 1, file_);
index 3f47fef..e411e12 100644 (file)
@@ -76,4 +76,50 @@ TEST_F(DepsLogTest, WriteRead) {
   ASSERT_EQ("bar.h", deps->nodes[1]->path());
 }
 
+// Verify that adding the same deps twice doesn't grow the file.
+TEST_F(DepsLogTest, DoubleEntry) {
+  // Write some deps to the file and grab its size.
+  int file_size;
+  {
+    State state;
+    DepsLog log;
+    string err;
+    EXPECT_TRUE(log.OpenForWrite(kTestFilename, &err));
+    ASSERT_EQ("", err);
+
+    vector<Node*> deps;
+    deps.push_back(state.GetNode("foo.h"));
+    deps.push_back(state.GetNode("bar.h"));
+    log.RecordDeps(state.GetNode("out.o"), 1, deps);
+    log.Close();
+
+    struct stat st;
+    ASSERT_EQ(0, stat(kTestFilename, &st));
+    file_size = (int)st.st_size;
+    ASSERT_GT(file_size, 0);
+  }
+
+  // Now reload the file, and readd the same deps.
+  {
+    State state;
+    DepsLog log;
+    string err;
+    EXPECT_TRUE(log.Load(kTestFilename, &state, &err));
+
+    EXPECT_TRUE(log.OpenForWrite(kTestFilename, &err));
+    ASSERT_EQ("", err);
+
+    vector<Node*> deps;
+    deps.push_back(state.GetNode("foo.h"));
+    deps.push_back(state.GetNode("bar.h"));
+    log.RecordDeps(state.GetNode("out.o"), 1, deps);
+    log.Close();
+
+    struct stat st;
+    ASSERT_EQ(0, stat(kTestFilename, &st));
+    int file_size_2 = (int)st.st_size;
+    ASSERT_EQ(file_size, file_size_2);
+  }
+}
+
 }  // anonymous namespace