summaryrefslogtreecommitdiffstats
path: root/src/deps_log_test.cc
diff options
context:
space:
mode:
authorEvan Martin <martine@danga.com>2013-04-27 20:39:04 (GMT)
committerEvan Martin <martine@danga.com>2013-04-27 20:39:04 (GMT)
commitb549d18748a82d2a0e0efccb5ac6d9e3714f5234 (patch)
tree6c4837a75a2bef428c8656cc7b425cc712907b9e /src/deps_log_test.cc
parent896b81c1fe50b11012a34365a11b8fcaba33350f (diff)
downloadNinja-b549d18748a82d2a0e0efccb5ac6d9e3714f5234.zip
Ninja-b549d18748a82d2a0e0efccb5ac6d9e3714f5234.tar.gz
Ninja-b549d18748a82d2a0e0efccb5ac6d9e3714f5234.tar.bz2
deps log: recover on truncated entry
If a read fails while reading an entry, truncate the log to the last successfully read entry. This prevents corruption when a subsequent run appends another entry.
Diffstat (limited to 'src/deps_log_test.cc')
-rw-r--r--src/deps_log_test.cc71
1 files changed, 68 insertions, 3 deletions
diff --git a/src/deps_log_test.cc b/src/deps_log_test.cc
index 40539a7..9623d17 100644
--- a/src/deps_log_test.cc
+++ b/src/deps_log_test.cc
@@ -218,8 +218,7 @@ TEST_F(DepsLogTest, InvalidHeader) {
}
}
-// Simulate what happens if a write gets interrupted and the resulting
-// file is truncated.
+// Simulate what happens when loading a truncated log file.
TEST_F(DepsLogTest, Truncated) {
// Create a file with some entries.
{
@@ -263,7 +262,7 @@ TEST_F(DepsLogTest, Truncated) {
break;
}
- ASSERT_GE(node_count, log.nodes().size());
+ ASSERT_GE(node_count, (int)log.nodes().size());
node_count = log.nodes().size();
// Count how many non-NULL deps entries there are.
@@ -278,4 +277,70 @@ TEST_F(DepsLogTest, Truncated) {
}
}
+// Run the truncation-recovery logic.
+TEST_F(DepsLogTest, TruncatedRecovery) {
+ // Create a file with some entries.
+ {
+ 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);
+
+ deps.clear();
+ deps.push_back(state.GetNode("foo.h"));
+ deps.push_back(state.GetNode("bar2.h"));
+ log.RecordDeps(state.GetNode("out2.o"), 2, deps);
+
+ log.Close();
+ }
+
+ // Shorten the file, corrupting the last record.
+ struct stat st;
+ ASSERT_EQ(0, stat(kTestFilename, &st));
+ ASSERT_EQ(0, truncate(kTestFilename, st.st_size - 2));
+
+ // Load the file again, add an entry.
+ {
+ State state;
+ DepsLog log;
+ string err;
+ EXPECT_TRUE(log.Load(kTestFilename, &state, &err));
+ ASSERT_EQ("premature end of file; recovering", err);
+ err.clear();
+
+ // The truncated entry should've been discarded.
+ EXPECT_EQ(NULL, log.GetDeps(state.GetNode("out2.o")));
+
+ EXPECT_TRUE(log.OpenForWrite(kTestFilename, &err));
+ ASSERT_EQ("", err);
+
+ // Add a new entry.
+ vector<Node*> deps;
+ deps.push_back(state.GetNode("foo.h"));
+ deps.push_back(state.GetNode("bar2.h"));
+ log.RecordDeps(state.GetNode("out2.o"), 3, deps);
+
+ log.Close();
+ }
+
+ // Load the file a third time to verify appending after a mangled
+ // entry doesn't break things.
+ {
+ State state;
+ DepsLog log;
+ string err;
+ EXPECT_TRUE(log.Load(kTestFilename, &state, &err));
+
+ // The truncated entry should exist.
+ DepsLog::Deps* deps = log.GetDeps(state.GetNode("out2.o"));
+ ASSERT_TRUE(deps);
+ }
+}
+
} // anonymous namespace