diff options
author | shess <shess@chromium.org> | 2015-10-06 10:39:16 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-10-06 17:39:52 +0000 |
commit | 7dbd4dee4702e30efb24c81898ae45dd0d502c41 (patch) | |
tree | 88ac7fb9857b0c80194ab219b5bcc40d19de8ac4 /sql/connection_unittest.cc | |
parent | 70b782d89203d62d8b4e7937615579a3fc04583b (diff) | |
download | chromium_src-7dbd4dee4702e30efb24c81898ae45dd0d502c41.zip chromium_src-7dbd4dee4702e30efb24c81898ae45dd0d502c41.tar.gz chromium_src-7dbd4dee4702e30efb24c81898ae45dd0d502c41.tar.bz2 |
[sql] Use memory-mapped I/O for sql::Connection.
sql::Connection::Open*() uses PRAGMA mmap_size to enable SQLite's
memory-mapped I/O. Additionally instrument to flush dirty pages from
the page cache after writes.
BUG=489784,533682,537681,537636
[Relands https://crrev.com/9a1948a4d6d4 (#350362),
reverted at https://crrev.com/55c3216b15ce (#350386),
relanded at https://crrev.com/5c2f4e50d96d (#351344),
reverted at https://crrev.com/745e18c52384 (#351596).
May the waterfall have mercy on my CL.]
Review URL: https://codereview.chromium.org/1382283003
Cr-Commit-Position: refs/heads/master@{#352631}
Diffstat (limited to 'sql/connection_unittest.cc')
-rw-r--r-- | sql/connection_unittest.cc | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/sql/connection_unittest.cc b/sql/connection_unittest.cc index 10a15a8..0038a1d 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,82 @@ TEST_F(SQLConnectionTest, TimeUpdateTransaction) { EXPECT_EQ(0, samples->sum()); } +// 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. +#if !defined(MOJO_APPTEST_IMPL) +TEST_F(SQLConnectionTest, MmapTest) { + // Skip the test for platforms which don't enable memory-mapped I/O in SQLite, + // or which don't even support the pragma. The former seems to apply to iOS, + // the latter to older iOS. + // TODO(shess): Disable test on iOS? Disable on USE_SYSTEM_SQLITE? + { + sql::Statement s(db().GetUniqueStatement("PRAGMA mmap_size")); + if (!s.Step() || !s.ColumnInt64(0)) + return; + } + + // The test re-uses the database file to make sure it's representative of a + // SQLite file, but will be storing incompatible data. + db().Close(); + + const uint32 kFlags = + base::File::FLAG_OPEN|base::File::FLAG_READ|base::File::FLAG_WRITE; + char buf[4096]; + + // Create a file with a block of '0', a block of '1', and a block of '2'. + { + base::File f(db_path(), kFlags); + ASSERT_TRUE(f.IsValid()); + 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. + { + base::File f(db_path(), kFlags); + ASSERT_TRUE(f.IsValid()); + 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))); + + // Repeat with a single '4' in case page-sized blocks are different. + const size_t kOffset = 1*sizeof(buf) + 123; + ASSERT_NE('4', m.data()[kOffset]); + { + base::File f(db_path(), kFlags); + ASSERT_TRUE(f.IsValid()); + buf[0] = '4'; + ASSERT_EQ(f.Write(kOffset, buf, 1), 1); + } + ASSERT_EQ('4', m.data()[kOffset]); + } +} +#endif + } // namespace |