Index: sql/connection_unittest.cc |
diff --git a/sql/connection_unittest.cc b/sql/connection_unittest.cc |
index 10a15a868908965d893ce4952388bd09688e4e19..5ce591a360d68f1cef18f72170a27fb2650bf787 100644 |
--- a/sql/connection_unittest.cc |
+++ b/sql/connection_unittest.cc |
@@ -4,10 +4,12 @@ |
#include "base/bind.h" |
#include "base/files/file_util.h" |
+#include "base/files/memory_mapped_file.h" |
#include "base/files/scoped_file.h" |
#include "base/files/scoped_temp_dir.h" |
#include "base/logging.h" |
#include "base/metrics/statistics_recorder.h" |
+#include "base/strings/stringprintf.h" |
#include "base/test/histogram_tester.h" |
#include "sql/connection.h" |
#include "sql/correct_sql_test_base.h" |
@@ -1298,4 +1300,54 @@ TEST_F(SQLConnectionTest, TimeUpdateTransaction) { |
EXPECT_EQ(0, samples->sum()); |
} |
-} // namespace |
+// Make sure that OS file writes to a mmap'ed file are reflected in the memory |
+// mapping of a memory-mapped file. Normally SQLite writes to memory-mapped |
+// files using memcpy(), which should stay consistent. Our SQLite is slightly |
+// patched to mmap read only, then write using OS file writes. If the |
+// memory-mapped version doesn't reflect the OS file writes, SQLite's |
+// memory-mapped I/O should be disabled on this platform. |
+TEST_F(SQLConnectionTest, MmapTest) { |
+ { |
+ sql::Statement s(db().GetUniqueStatement("PRAGMA mmap_size")); |
+ ASSERT_TRUE(s.Step()); |
+ EXPECT_GT(s.ColumnInt64(0), 0); |
+ } |
+ db().Close(); |
+ const uint32 kFlags = |
+ base::File::FLAG_OPEN_ALWAYS|base::File::FLAG_READ|base::File::FLAG_WRITE; |
+ base::File f(db_path(), kFlags); |
+ ASSERT_TRUE(f.IsValid()); |
+ |
+ // Create a file with a block of '0', a block of '1', and a block of '2'. |
+ char buf[4096]; |
+ memset(buf, '0', sizeof(buf)); |
+ ASSERT_EQ(f.Write(0*sizeof(buf), buf, sizeof(buf)), (int)sizeof(buf)); |
+ |
+ memset(buf, '1', sizeof(buf)); |
+ ASSERT_EQ(f.Write(1*sizeof(buf), buf, sizeof(buf)), (int)sizeof(buf)); |
+ |
+ memset(buf, '2', sizeof(buf)); |
+ ASSERT_EQ(f.Write(2*sizeof(buf), buf, sizeof(buf)), (int)sizeof(buf)); |
+ |
+ // mmap the file and verify that everything looks right. |
+ base::MemoryMappedFile m; |
+ ASSERT_TRUE(m.Initialize(db_path())); |
+ |
+ memset(buf, '0', sizeof(buf)); |
+ ASSERT_EQ(0, memcmp(buf, m.data() + 0*sizeof(buf), sizeof(buf))); |
+ |
+ memset(buf, '1', sizeof(buf)); |
+ ASSERT_EQ(0, memcmp(buf, m.data() + 1*sizeof(buf), sizeof(buf))); |
+ |
+ memset(buf, '2', sizeof(buf)); |
+ ASSERT_EQ(0, memcmp(buf, m.data() + 2*sizeof(buf), sizeof(buf))); |
+ |
+ // Scribble some '3' into the first page of the file, and verify that it looks |
+ // the same in the memory mapping. |
+ memset(buf, '3', sizeof(buf)); |
+ ASSERT_EQ(f.Write(0*sizeof(buf), buf, sizeof(buf)), (int)sizeof(buf)); |
+ ASSERT_EQ(0, memcmp(buf, m.data() + 0*sizeof(buf), sizeof(buf))); |
rmcilroy
2015/09/17 17:17:44
Are we sure that this atomic on all platforms we c
Scott Hess - ex-Googler
2015/09/17 21:14:37
Ooooh, thanks for pointing this out, I hadn't thou
|
+ |
+} |
+ |
+} // namespace sql |