diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-07-17 13:57:45 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-07-19 13:44:40 +0000 |
commit | 6ec7b8da05d21a3878bd21c691b41e675d74bb1c (patch) | |
tree | b87f250bc19413750b9bb9cdbf2da20ef5014820 /chromium/sql | |
parent | ec02ee4181c49b61fce1c8fb99292dbb8139cc90 (diff) | |
download | qtwebengine-chromium-6ec7b8da05d21a3878bd21c691b41e675d74bb1c.tar.gz |
BASELINE: Update Chromium to 60.0.3112.70
Change-Id: I9911c2280a014d4632f254857876a395d4baed2d
Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/sql')
-rw-r--r-- | chromium/sql/OWNERS | 3 | ||||
-rw-r--r-- | chromium/sql/connection.cc | 9 | ||||
-rw-r--r-- | chromium/sql/connection.h | 1 | ||||
-rw-r--r-- | chromium/sql/connection_unittest.cc | 36 | ||||
-rw-r--r-- | chromium/sql/sqlite_features_unittest.cc | 78 |
5 files changed, 106 insertions, 21 deletions
diff --git a/chromium/sql/OWNERS b/chromium/sql/OWNERS index 9a8c2d281de..a4209042eed 100644 --- a/chromium/sql/OWNERS +++ b/chromium/sql/OWNERS @@ -1,2 +1,5 @@ michaeln@chromium.org pwnall@chromium.org + +# TEAM: storage-dev@chromium.org +# COMPONENT: Blink>Storage diff --git a/chromium/sql/connection.cc b/chromium/sql/connection.cc index 0511e11b5c5..c80758f3d6b 100644 --- a/chromium/sql/connection.cc +++ b/chromium/sql/connection.cc @@ -1112,6 +1112,15 @@ bool Connection::Raze() { // page_size" can be used to query such a database. ScopedWritableSchema writable_schema(db_); +#if defined(OS_WIN) + // On Windows, truncate silently fails when applied to memory-mapped files. + // Disable memory-mapping so that the truncate succeeds. Note that other + // connections may have memory-mapped the file, so this may not entirely + // prevent the problem. + // [Source: <https://sqlite.org/mmap.html> plus experiments.] + ignore_result(Execute("PRAGMA mmap_size = 0")); +#endif + const char* kMain = "main"; int rc = BackupDatabase(null_db.db_, db_, kMain); UMA_HISTOGRAM_SPARSE_SLOWLY("Sqlite.RazeDatabase",rc); diff --git a/chromium/sql/connection.h b/chromium/sql/connection.h index 639c333ed4d..838d552cdfd 100644 --- a/chromium/sql/connection.h +++ b/chromium/sql/connection.h @@ -527,6 +527,7 @@ class SQL_EXPORT Connection { FRIEND_TEST_ALL_PREFIXES(SQLConnectionTest, GetAppropriateMmapSizeAltStatus); FRIEND_TEST_ALL_PREFIXES(SQLConnectionTest, OnMemoryDump); FRIEND_TEST_ALL_PREFIXES(SQLConnectionTest, RegisterIntentToUpload); + FRIEND_TEST_ALL_PREFIXES(SQLiteFeaturesTest, WALNoClose); // Internal initialize function used by both Init and InitInMemory. The file // name is always 8 bits since we want to use the 8-bit version of diff --git a/chromium/sql/connection_unittest.cc b/chromium/sql/connection_unittest.cc index 6ac4f8bc12d..4ee8b0288a3 100644 --- a/chromium/sql/connection_unittest.cc +++ b/chromium/sql/connection_unittest.cc @@ -854,6 +854,42 @@ TEST_F(SQLConnectionTest, RazeAndCloseDiagnostics) { // closely match real life. That would also allow testing // RazeWithTimeout(). +// On Windows, truncate silently fails against a memory-mapped file. One goal +// of Raze() is to truncate the file to remove blocks which generate I/O errors. +// Test that Raze() turns off memory mapping so that the file is truncated. +// [This would not cover the case of multiple connections where one of the other +// connections is memory-mapped. That is infrequent in Chromium.] +TEST_F(SQLConnectionTest, RazeTruncate) { + // The empty database has 0 or 1 pages. Raze() should leave it with exactly 1 + // page. Not checking directly because auto_vacuum on Android adds a freelist + // page. + ASSERT_TRUE(db().Raze()); + int64_t expected_size; + ASSERT_TRUE(base::GetFileSize(db_path(), &expected_size)); + ASSERT_GT(expected_size, 0); + + // Cause the database to take a few pages. + const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)"; + ASSERT_TRUE(db().Execute(kCreateSql)); + for (size_t i = 0; i < 24; ++i) { + ASSERT_TRUE( + db().Execute("INSERT INTO foo (value) VALUES (randomblob(1024))")); + } + int64_t db_size; + ASSERT_TRUE(base::GetFileSize(db_path(), &db_size)); + ASSERT_GT(db_size, expected_size); + + // Make a query covering most of the database file to make sure that the + // blocks are actually mapped into memory. Empirically, the truncate problem + // doesn't seem to happen if no blocks are mapped. + EXPECT_EQ("24576", + ExecuteWithResult(&db(), "SELECT SUM(LENGTH(value)) FROM foo")); + + ASSERT_TRUE(db().Raze()); + ASSERT_TRUE(base::GetFileSize(db_path(), &db_size)); + ASSERT_EQ(expected_size, db_size); +} + #if defined(OS_ANDROID) TEST_F(SQLConnectionTest, SetTempDirForSQL) { diff --git a/chromium/sql/sqlite_features_unittest.cc b/chromium/sql/sqlite_features_unittest.cc index 0f124af3c50..88f7802fc02 100644 --- a/chromium/sql/sqlite_features_unittest.cc +++ b/chromium/sql/sqlite_features_unittest.cc @@ -32,8 +32,12 @@ // Test that certain features are/are-not enabled in our SQLite. +namespace sql { namespace { +using sql::test::ExecuteWithResult; +using sql::test::ExecuteWithResults; + void CaptureErrorCallback(int* error_pointer, std::string* sql_text, int error, sql::Statement* stmt) { *error_pointer = error; @@ -41,6 +45,8 @@ void CaptureErrorCallback(int* error_pointer, std::string* sql_text, *sql_text = text ? text : "no statement available"; } +} // namespace + class SQLiteFeaturesTest : public sql::SQLTestBase { public: SQLiteFeaturesTest() : error_(SQLITE_OK) {} @@ -102,10 +108,8 @@ TEST_F(SQLiteFeaturesTest, FTS3_Prefix) { ASSERT_TRUE(db().Execute("INSERT INTO foo (x) VALUES ('test')")); - sql::Statement s(db().GetUniqueStatement( - "SELECT x FROM foo WHERE x MATCH 'te*'")); - ASSERT_TRUE(s.Step()); - EXPECT_EQ("test", s.ColumnString(0)); + EXPECT_EQ("test", + ExecuteWithResult(&db(), "SELECT x FROM foo WHERE x MATCH 'te*'")); } #endif @@ -118,10 +122,9 @@ TEST_F(SQLiteFeaturesTest, UsesUsleep) { sqlite3_sleep(1); base::TimeDelta delta = base::TimeTicks::Now() - before; - // It is not impossible for this to be over 1000 if things are compiled the - // right way. But it is very unlikely, most platforms seem to be around - // <TBD>. - LOG(ERROR) << "Milliseconds: " << delta.InMilliseconds(); + // It is not impossible for this to be over 1000 if things are compiled + // correctly, but that is very unlikely. Most platforms seem to be exactly + // 1ms, with the rest at 2ms, and the worst observed cases was ASAN at 7ms. EXPECT_LT(delta.InMilliseconds(), 1000); } #endif @@ -135,28 +138,29 @@ TEST_F(SQLiteFeaturesTest, ForeignKeySupport) { "CREATE TABLE children (" " id INTEGER PRIMARY KEY," " pid INTEGER NOT NULL REFERENCES parents(id) ON DELETE CASCADE)")); + const char kSelectParents[] = "SELECT * FROM parents ORDER BY id"; + const char kSelectChildren[] = "SELECT * FROM children ORDER BY id"; // Inserting without a matching parent should fail with constraint violation. // Mask off any extended error codes for USE_SYSTEM_SQLITE. - int insertErr = db().ExecuteAndReturnErrorCode( - "INSERT INTO children VALUES (10, 1)"); - EXPECT_EQ(SQLITE_CONSTRAINT, (insertErr&0xff)); - - size_t rows; - EXPECT_TRUE(sql::test::CountTableRows(&db(), "children", &rows)); - EXPECT_EQ(0u, rows); + EXPECT_EQ("", ExecuteWithResult(&db(), kSelectParents)); + const int insert_error = + db().ExecuteAndReturnErrorCode("INSERT INTO children VALUES (10, 1)"); + EXPECT_EQ(SQLITE_CONSTRAINT, (insert_error & 0xff)); + EXPECT_EQ("", ExecuteWithResult(&db(), kSelectChildren)); // Inserting with a matching parent should work. ASSERT_TRUE(db().Execute("INSERT INTO parents VALUES (1)")); + EXPECT_EQ("1", ExecuteWithResults(&db(), kSelectParents, "|", "\n")); EXPECT_TRUE(db().Execute("INSERT INTO children VALUES (11, 1)")); EXPECT_TRUE(db().Execute("INSERT INTO children VALUES (12, 1)")); - EXPECT_TRUE(sql::test::CountTableRows(&db(), "children", &rows)); - EXPECT_EQ(2u, rows); + EXPECT_EQ("11|1\n12|1", + ExecuteWithResults(&db(), kSelectChildren, "|", "\n")); - // Deleting the parent should cascade, i.e., delete the children as well. + // Deleting the parent should cascade, deleting the children as well. ASSERT_TRUE(db().Execute("DELETE FROM parents")); - EXPECT_TRUE(sql::test::CountTableRows(&db(), "children", &rows)); - EXPECT_EQ(0u, rows); + EXPECT_EQ("", ExecuteWithResult(&db(), kSelectParents)); + EXPECT_EQ("", ExecuteWithResult(&db(), kSelectChildren)); } #if defined(MOJO_APPTEST_IMPL) || defined(OS_IOS) @@ -453,4 +457,36 @@ TEST_F(SQLiteFeaturesTest, SmartAutoVacuum) { } #endif // !defined(USE_SYSTEM_SQLITE) -} // namespace +#if !defined(USE_SYSTEM_SQLITE) +// SQLite WAL mode defaults to checkpointing the WAL on close. This would push +// additional work into Chromium shutdown. Verify that SQLite supports a config +// option to not checkpoint on close. +TEST_F(SQLiteFeaturesTest, WALNoClose) { + base::FilePath wal_path(db_path().value() + FILE_PATH_LITERAL("-wal")); + + // Turn on WAL mode, then verify that the mode changed (WAL is supported). + ASSERT_TRUE(db().Execute("PRAGMA journal_mode = WAL")); + ASSERT_EQ("wal", ExecuteWithResult(&db(), "PRAGMA journal_mode")); + + // The WAL file is created lazily on first change. + ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)")); + + // By default, the WAL is checkpointed then deleted on close. + ASSERT_TRUE(GetPathExists(wal_path)); + db().Close(); + ASSERT_FALSE(GetPathExists(wal_path)); + + // Reopen and configure the database to not checkpoint WAL on close. + ASSERT_TRUE(Reopen()); + ASSERT_TRUE(db().Execute("PRAGMA journal_mode = WAL")); + ASSERT_TRUE(db().Execute("ALTER TABLE foo ADD COLUMN c")); + ASSERT_EQ( + SQLITE_OK, + sqlite3_db_config(db().db_, SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE, 1, NULL)); + ASSERT_TRUE(GetPathExists(wal_path)); + db().Close(); + ASSERT_TRUE(GetPathExists(wal_path)); +} +#endif + +} // namespace sql |