From 578b70e998b5fa5a54bf3e4f8ddea230a63e7986 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Thu, 25 Jul 2019 15:01:25 +0200 Subject: [PATCH] Clang: Add fetchTimeStamps to PrecompiledHeaderStorage Change-Id: I75552a971fbc39a81e14e3b9ec0c5125d3858025 Reviewed-by: Tim Jenssen --- src/libs/clangsupport/sourceentry.h | 13 ++++ .../source/precompiledheaderstorage.h | 24 +++++++ .../precompiledheaderstorageinterface.h | 1 + .../unittest/mockprecompiledheaderstorage.h | 3 + .../unit/unittest/mocksqlitereadstatement.cpp | 7 ++ tests/unit/unittest/mocksqlitereadstatement.h | 16 +++-- .../precompiledheaderstorage-test.cpp | 69 +++++++++++++++++++ 7 files changed, 128 insertions(+), 5 deletions(-) diff --git a/src/libs/clangsupport/sourceentry.h b/src/libs/clangsupport/sourceentry.h index 5e8769d14fd..4912b367c39 100644 --- a/src/libs/clangsupport/sourceentry.h +++ b/src/libs/clangsupport/sourceentry.h @@ -59,6 +59,19 @@ public: int64 value = -1; }; +class PrecompiledHeaderTimeStamps +{ +public: + PrecompiledHeaderTimeStamps() = default; + PrecompiledHeaderTimeStamps(long long projectTimeStamp, long long systemTimeStamp) + : project(projectTimeStamp) + , system(systemTimeStamp) + {} + + TimeStamp project; + TimeStamp system; +}; + class SourceTimeStamp { using int64 = long long; diff --git a/src/tools/clangpchmanagerbackend/source/precompiledheaderstorage.h b/src/tools/clangpchmanagerbackend/source/precompiledheaderstorage.h index 16a956b2adc..30b4c0e1df1 100644 --- a/src/tools/clangpchmanagerbackend/source/precompiledheaderstorage.h +++ b/src/tools/clangpchmanagerbackend/source/precompiledheaderstorage.h @@ -182,6 +182,26 @@ public: return {}; } + PrecompiledHeaderTimeStamps fetchTimeStamps(ProjectPartId projectPartId) const override + { + try { + Sqlite::DeferredTransaction transaction{database}; + + auto value = fetchTimeStampsStatement.template value( + projectPartId.projectPathId); + + transaction.commit(); + + if (value) + return *value; + + } catch (const Sqlite::StatementIsBusy) { + return fetchTimeStamps(projectPartId); + } + + return {}; + } + public: Sqlite::ImmediateNonThrowingDestructorTransaction transaction; Database &database; @@ -216,6 +236,10 @@ public: mutable ReadStatement fetchPrecompiledHeadersStatement{ "SELECT projectPchPath, systemPchPath FROM precompiledHeaders WHERE projectPartId = ?", database}; + mutable ReadStatement fetchTimeStampsStatement{ + "SELECT projectPchBuildTime, systemPchBuildTime FROM precompiledHeaders WHERE " + "projectPartId = ?", + database}; }; } diff --git a/src/tools/clangpchmanagerbackend/source/precompiledheaderstorageinterface.h b/src/tools/clangpchmanagerbackend/source/precompiledheaderstorageinterface.h index bafbc7ace86..dacdbe9e177 100644 --- a/src/tools/clangpchmanagerbackend/source/precompiledheaderstorageinterface.h +++ b/src/tools/clangpchmanagerbackend/source/precompiledheaderstorageinterface.h @@ -58,6 +58,7 @@ public: virtual FilePath fetchSystemPrecompiledHeaderPath(ProjectPartId projectPartId) = 0; virtual FilePath fetchPrecompiledHeader(ProjectPartId projectPartId) const = 0; virtual PchPaths fetchPrecompiledHeaders(ProjectPartId projectPartId) const = 0; + virtual PrecompiledHeaderTimeStamps fetchTimeStamps(ProjectPartId projectPartId) const = 0; protected: ~PrecompiledHeaderStorageInterface() = default; diff --git a/tests/unit/unittest/mockprecompiledheaderstorage.h b/tests/unit/unittest/mockprecompiledheaderstorage.h index f25350200d1..4d6fecbbfe3 100644 --- a/tests/unit/unittest/mockprecompiledheaderstorage.h +++ b/tests/unit/unittest/mockprecompiledheaderstorage.h @@ -52,4 +52,7 @@ public: ClangBackEnd::FilePath(ClangBackEnd::ProjectPartId projectPartId)); MOCK_CONST_METHOD1(fetchPrecompiledHeaders, ClangBackEnd::PchPaths(ClangBackEnd::ProjectPartId projectPartId)); + MOCK_CONST_METHOD1( + fetchTimeStamps, + ClangBackEnd::PrecompiledHeaderTimeStamps(ClangBackEnd::ProjectPartId projectPartId)); }; diff --git a/tests/unit/unittest/mocksqlitereadstatement.cpp b/tests/unit/unittest/mocksqlitereadstatement.cpp index 1e800e2be15..eb68dcc9c9a 100644 --- a/tests/unit/unittest/mocksqlitereadstatement.cpp +++ b/tests/unit/unittest/mocksqlitereadstatement.cpp @@ -253,3 +253,10 @@ MockSqliteReadStatement::value(const int & { return valueReturnSourceNameAndDirectoryId(id); } + +template<> +Utils::optional +MockSqliteReadStatement::value(const int &projectPartId) +{ + return valuesReturnPrecompiledHeaderTimeStamps(projectPartId); +} diff --git a/tests/unit/unittest/mocksqlitereadstatement.h b/tests/unit/unittest/mocksqlitereadstatement.h index 191c38accdd..5386c139079 100644 --- a/tests/unit/unittest/mocksqlitereadstatement.h +++ b/tests/unit/unittest/mocksqlitereadstatement.h @@ -57,9 +57,10 @@ using ClangRefactoring::SourceLocation; using ClangRefactoring::SourceLocations; using std::int64_t; namespace Sources = ClangBackEnd::Sources; +using ClangBackEnd::PrecompiledHeaderTimeStamps; +using ClangBackEnd::UsedMacros; using ClangRefactoring::Symbol; using ClangRefactoring::Symbols; -using ClangBackEnd::UsedMacros; class MockSqliteDatabase; @@ -142,10 +143,11 @@ public: MOCK_METHOD1(valuesReturnSourceTimeStamps, SourceTimeStamps(std::size_t)); MOCK_METHOD2(valuesReturnSourceTimeStamps, SourceTimeStamps(std::size_t, int sourcePathId)); - template - std::vector values(std::size_t reserveSize, const QueryType&... queryValues); + MOCK_METHOD1(valuesReturnPrecompiledHeaderTimeStamps, + PrecompiledHeaderTimeStamps(int projectPartId)); + + template + std::vector values(std::size_t reserveSize, const QueryType &... queryValues); template (std::size_t template <> Utils::optional MockSqliteReadStatement::value(const int&); + +template<> +Utils::optional +MockSqliteReadStatement::value(const int &); diff --git a/tests/unit/unittest/precompiledheaderstorage-test.cpp b/tests/unit/unittest/precompiledheaderstorage-test.cpp index d01f724df33..d2b14d290c2 100644 --- a/tests/unit/unittest/precompiledheaderstorage-test.cpp +++ b/tests/unit/unittest/precompiledheaderstorage-test.cpp @@ -51,6 +51,7 @@ protected: MockSqliteReadStatement &fetchSystemPrecompiledHeaderPathStatement = storage.fetchSystemPrecompiledHeaderPathStatement; MockSqliteReadStatement &fetchPrecompiledHeaderStatement = storage.fetchPrecompiledHeaderStatement; MockSqliteReadStatement &fetchPrecompiledHeadersStatement = storage.fetchPrecompiledHeadersStatement; + MockSqliteReadStatement &fetchTimeStampsStatement = storage.fetchTimeStampsStatement; }; TEST_F(PrecompiledHeaderStorage, UseTransaction) @@ -339,4 +340,72 @@ TEST_F(PrecompiledHeaderStorage, FetchEmptyPrecompiledHeaders) Field(&ClangBackEnd::PchPaths::systemPchPath, IsEmpty()))); } +TEST_F(PrecompiledHeaderStorage, FetchTimeStamps) +{ + ClangBackEnd::PrecompiledHeaderTimeStamps precompiledHeaderTimeStamps{22, 33}; + ON_CALL(fetchTimeStampsStatement, valuesReturnPrecompiledHeaderTimeStamps(Eq(23))) + .WillByDefault(Return(precompiledHeaderTimeStamps)); + + auto timeStamps = storage.fetchTimeStamps(23); + + ASSERT_THAT(timeStamps, + AllOf(Field(&ClangBackEnd::PrecompiledHeaderTimeStamps::project, Eq(22)), + Field(&ClangBackEnd::PrecompiledHeaderTimeStamps::system, Eq(33)))); +} + +TEST_F(PrecompiledHeaderStorage, NoFetchTimeStamps) +{ + auto timeStamps = storage.fetchTimeStamps(23); + + ASSERT_THAT(timeStamps, + AllOf(Field(&ClangBackEnd::PrecompiledHeaderTimeStamps::project, Eq(-1)), + Field(&ClangBackEnd::PrecompiledHeaderTimeStamps::system, Eq(-1)))); +} + +TEST_F(PrecompiledHeaderStorage, FetchTimeStampsCalls) +{ + InSequence s; + + EXPECT_CALL(database, deferredBegin()); + EXPECT_CALL(fetchTimeStampsStatement, valuesReturnPrecompiledHeaderTimeStamps(Eq(23))); + EXPECT_CALL(database, commit()); + + storage.fetchTimeStamps(23); +} + +TEST_F(PrecompiledHeaderStorage, FetchTimeStampsBusy) +{ + InSequence s; + + EXPECT_CALL(database, deferredBegin()); + EXPECT_CALL(fetchTimeStampsStatement, valuesReturnPrecompiledHeaderTimeStamps(Eq(23))) + .WillOnce(Throw(Sqlite::StatementIsBusy{""})); + EXPECT_CALL(database, rollback()); + EXPECT_CALL(database, deferredBegin()); + EXPECT_CALL(fetchTimeStampsStatement, valuesReturnPrecompiledHeaderTimeStamps(Eq(23))); + EXPECT_CALL(database, commit()); + + storage.fetchTimeStamps(23); +} + +class PrecompiledHeaderStorageSlowTest : public testing::Test +{ +protected: + Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory}; + ClangBackEnd::RefactoringDatabaseInitializer initializer{database}; + ClangBackEnd::PrecompiledHeaderStorage<> storage{database}; +}; + +TEST_F(PrecompiledHeaderStorageSlowTest, NoFetchTimeStamps) +{ + storage.insertProjectPrecompiledHeader(23, {}, 22); + storage.insertSystemPrecompiledHeaders({23}, {}, 33); + + auto timeStamps = storage.fetchTimeStamps(23); + + ASSERT_THAT(timeStamps, + AllOf(Field(&ClangBackEnd::PrecompiledHeaderTimeStamps::project, Eq(22)), + Field(&ClangBackEnd::PrecompiledHeaderTimeStamps::system, Eq(33)))); +} + } // namespace