diff --git a/src/libs/clangsupport/filepathcache.h b/src/libs/clangsupport/filepathcache.h index 9a90d71497d..ecc84570285 100644 --- a/src/libs/clangsupport/filepathcache.h +++ b/src/libs/clangsupport/filepathcache.h @@ -33,6 +33,8 @@ #include "filepathview.h" #include "stringcache.h" +#include + #include namespace ClangBackEnd { @@ -161,25 +163,35 @@ public: return m_fileNameCache.string(filePathId.filePathId, fetchSoureNameAndDirectoryId).directoryId; } - void addFilePaths(FilePathViews &&filePaths) + template + void addFilePaths(Container &&filePaths) { auto directoryPaths = Utils::transform>( filePaths, [](FilePathView filePath) { return filePath.directory(); }); - m_directoryPathCache.addStrings(std::move(directoryPaths), - [&](Utils::SmallStringView directoryPath) { - return m_filePathStorage.fetchDirectoryIdUnguarded( - directoryPath); - }); + std::unique_ptr transaction; + + m_directoryPathCache.addStrings(std::move(directoryPaths), [&](Utils::SmallStringView directoryPath) { + if (!transaction) + transaction = std::make_unique( + m_filePathStorage.database()); + return m_filePathStorage.fetchDirectoryIdUnguarded(directoryPath); + }); auto sourcePaths = Utils::transform>(filePaths, [&](FilePathView filePath) { return FileNameView{filePath.name(), m_directoryPathCache.stringId(filePath.directory())}; }); m_fileNameCache.addStrings(std::move(sourcePaths), [&](FileNameView fileNameView) { + if (!transaction) + transaction = std::make_unique( + m_filePathStorage.database()); return m_filePathStorage.fetchSourceIdUnguarded(fileNameView.directoryId, fileNameView.fileName); }); + + if (transaction) + transaction->commit(); } private: diff --git a/src/libs/clangsupport/filepathcaching.cpp b/src/libs/clangsupport/filepathcaching.cpp index 4464ea8201a..e2b23e7ad66 100644 --- a/src/libs/clangsupport/filepathcaching.cpp +++ b/src/libs/clangsupport/filepathcaching.cpp @@ -52,6 +52,11 @@ DirectoryPathId FilePathCaching::directoryPathId(FilePathId filePathId) const return m_cache.directoryPathId(filePathId); } +void FilePathCaching::addFilePaths(const FilePaths &filePaths) +{ + m_cache.addFilePaths(filePaths); +} + FilePathId CopyableFilePathCaching::filePathId(FilePathView filePath) const { return m_cache.filePathId(filePath); @@ -77,4 +82,9 @@ DirectoryPathId CopyableFilePathCaching::directoryPathId(FilePathId filePathId) return m_cache.directoryPathId(filePathId); } +void CopyableFilePathCaching::addFilePaths(const FilePaths &filePaths) +{ + m_cache.addFilePaths(filePaths); +} + } // namespace ClangBackEnd diff --git a/src/libs/clangsupport/filepathcaching.h b/src/libs/clangsupport/filepathcaching.h index 8bbbe0e43e0..17f1fb1d0e3 100644 --- a/src/libs/clangsupport/filepathcaching.h +++ b/src/libs/clangsupport/filepathcaching.h @@ -55,6 +55,7 @@ public: DirectoryPathId directoryPathId(Utils::SmallStringView directoryPath) const override; Utils::PathString directoryPath(DirectoryPathId directoryPathId) const override; DirectoryPathId directoryPathId(FilePathId filePathId) const override; + void addFilePaths(const ClangBackEnd::FilePaths &filePaths) override; private: Factory m_factory; @@ -78,6 +79,7 @@ public: DirectoryPathId directoryPathId(Utils::SmallStringView directoryPath) const override; Utils::PathString directoryPath(DirectoryPathId directoryPathId) const override; DirectoryPathId directoryPathId(FilePathId filePathId) const override; + void addFilePaths(const ClangBackEnd::FilePaths &filePaths) override; private: Cache m_cache; diff --git a/src/libs/clangsupport/filepathcachinginterface.h b/src/libs/clangsupport/filepathcachinginterface.h index 53cdc3515b9..67e30d1c5ce 100644 --- a/src/libs/clangsupport/filepathcachinginterface.h +++ b/src/libs/clangsupport/filepathcachinginterface.h @@ -44,6 +44,7 @@ public: virtual DirectoryPathId directoryPathId(Utils::SmallStringView directoryPath) const = 0; virtual DirectoryPathId directoryPathId(FilePathId filePathId) const = 0; virtual Utils::PathString directoryPath(DirectoryPathId directoryPathId) const = 0; + virtual void addFilePaths(const ClangBackEnd::FilePaths &filePaths) = 0; template FilePathIds filePathIds(Container &&filePaths) const diff --git a/src/libs/clangsupport/filepathstorage.h b/src/libs/clangsupport/filepathstorage.h index 3d6ca792dec..083782fec28 100644 --- a/src/libs/clangsupport/filepathstorage.h +++ b/src/libs/clangsupport/filepathstorage.h @@ -235,6 +235,8 @@ public: } } + Database &database() { return m_statementFactory.database; } + private: StatementFactory &m_statementFactory; }; diff --git a/src/plugins/clangpchmanager/projectupdater.cpp b/src/plugins/clangpchmanager/projectupdater.cpp index c3e8e65fa59..5bb1cf5ccda 100644 --- a/src/plugins/clangpchmanager/projectupdater.cpp +++ b/src/plugins/clangpchmanager/projectupdater.cpp @@ -67,8 +67,11 @@ public: void ProjectUpdater::updateProjectParts(const std::vector &projectParts, Utils::SmallStringVector &&toolChainArguments) { - m_server.updateProjectParts(ClangBackEnd::UpdateProjectPartsMessage{ - toProjectPartContainers(projectParts), std::move(toolChainArguments)}); + addProjectFilesToFilePathCache(projectParts); + + m_server.updateProjectParts( + ClangBackEnd::UpdateProjectPartsMessage{toProjectPartContainers(projectParts), + std::move(toolChainArguments)}); } void ProjectUpdater::removeProjectParts(ClangBackEnd::ProjectPartIds projectPartIds) @@ -432,4 +435,24 @@ ClangBackEnd::ProjectPartIds ProjectUpdater::toProjectPartIds( return projectPartIds; } +void ProjectUpdater::addProjectFilesToFilePathCache(const std::vector &projectParts) +{ + std::size_t fileCount = std::accumulate(projectParts.begin(), + projectParts.end(), + std::size_t(0), + [](std::size_t value, CppTools::ProjectPart *projectPart) { + return value + std::size_t(projectPart->files.size()); + }); + ClangBackEnd::FilePaths filePaths; + filePaths.reserve(fileCount); + + for (CppTools::ProjectPart *projectPart : projectParts) { + for (const CppTools::ProjectFile &file : projectPart->files) + if (file.active) + filePaths.emplace_back(file.path); + } + + m_filePathCache.addFilePaths(filePaths); +} + } // namespace ClangPchManager diff --git a/src/plugins/clangpchmanager/projectupdater.h b/src/plugins/clangpchmanager/projectupdater.h index 4c4300d194e..c3f793dc2fd 100644 --- a/src/plugins/clangpchmanager/projectupdater.h +++ b/src/plugins/clangpchmanager/projectupdater.h @@ -115,6 +115,9 @@ public: ClangBackEnd::ProjectPartIds toProjectPartIds(const QStringList &projectPartNames) const; +private: + void addProjectFilesToFilePathCache(const std::vector &projectParts); + private: ClangBackEnd::GeneratedFiles m_generatedFiles; ClangBackEnd::FilePaths m_excludedPaths; diff --git a/tests/unit/unittest/filepathcache-test.cpp b/tests/unit/unittest/filepathcache-test.cpp index c46bb0ce880..789eb664511 100644 --- a/tests/unit/unittest/filepathcache-test.cpp +++ b/tests/unit/unittest/filepathcache-test.cpp @@ -26,6 +26,7 @@ #include "googletest.h" #include "mockfilepathstorage.h" +#include "mocksqlitedatabase.h" #include @@ -37,6 +38,7 @@ using Cache = ClangBackEnd::FilePathCache>; using ClangBackEnd::FilePathId; using NFP = ClangBackEnd::FilePath; using ClangBackEnd::FilePathView; +using ClangBackEnd::FilePathViews; using ClangBackEnd::Sources::SourceNameAndDirectoryId; class FilePathCache : public testing::Test @@ -73,9 +75,10 @@ protected: } protected: - NiceMock mockStorage; + NiceMock mockDatabase; + NiceMock mockStorage{mockDatabase}; Cache cache{mockStorage}; - NiceMock mockStorageFilled; + NiceMock mockStorageFilled{mockDatabase}; }; TEST_F(FilePathCache, FilePathIdWithOutAnyEntryCallDirectoryId) @@ -379,7 +382,7 @@ TEST_F(FilePathCache, GetFileIdAfterAddFilePaths) Cache cacheFilled{mockStorageFilled}; cacheFilled.addFilePaths( - {"/path3/to/file.h", "/path/to/file.h", "/path2/to/file2.h", "/path/to/file.cpp"}); + FilePathViews{"/path3/to/file.h", "/path/to/file.h", "/path2/to/file2.h", "/path/to/file.cpp"}); ASSERT_THAT(cacheFilled.filePath(101), Eq("/path3/to/file.h")); } @@ -388,7 +391,7 @@ TEST_F(FilePathCache, GetFileIdAfterAddFilePathsWhichWasAlreadyAdded) { Cache cacheFilled{mockStorageFilled}; - cacheFilled.addFilePaths({"/path3/to/file.h", "/path/to/file.h", "/path2/to/file2.h"}); + cacheFilled.addFilePaths(FilePathViews{"/path3/to/file.h", "/path/to/file.h", "/path2/to/file2.h"}); ASSERT_THAT(cacheFilled.filePath(42), Eq("/path/to/file.cpp")); } @@ -398,13 +401,42 @@ TEST_F(FilePathCache, AddFilePathsCalls) Cache cacheFilled{mockStorageFilled}; InSequence s; + EXPECT_CALL(mockDatabase, deferredBegin()); EXPECT_CALL(mockStorageFilled, fetchDirectoryIdUnguarded(Eq("/path3/to"))).WillOnce(Return(7)); + EXPECT_CALL(mockStorageFilled, fetchDirectoryIdUnguarded(Eq("/path/to"))).Times(0); EXPECT_CALL(mockStorageFilled, fetchSourceIdUnguarded(5, Eq("file.h"))).WillOnce(Return(99)); EXPECT_CALL(mockStorageFilled, fetchSourceIdUnguarded(6, Eq("file2.h"))).WillOnce(Return(106)); EXPECT_CALL(mockStorageFilled, fetchSourceIdUnguarded(7, Eq("file.h"))).WillOnce(Return(101)); + EXPECT_CALL(mockStorageFilled, fetchSourceIdUnguarded(5, Eq("file.cpp"))).Times(0); + EXPECT_CALL(mockDatabase, commit()); cacheFilled.addFilePaths( - {"/path3/to/file.h", "/path/to/file.h", "/path2/to/file2.h", "/path/to/file.cpp"}); + FilePathViews{"/path3/to/file.h", "/path/to/file.h", "/path2/to/file2.h", "/path/to/file.cpp"}); } +TEST_F(FilePathCache, DontUseTransactionIfNotAddingFilesInAddFilePathsCalls) +{ + Cache cacheFilled{mockStorageFilled}; + InSequence s; + + EXPECT_CALL(mockDatabase, deferredBegin()).Times(0); + EXPECT_CALL(mockStorageFilled, fetchDirectoryIdUnguarded(Eq("/path/to"))).Times(0); + EXPECT_CALL(mockStorageFilled, fetchSourceIdUnguarded(5, Eq("file.cpp"))).Times(0); + EXPECT_CALL(mockDatabase, commit()).Times(0); + + cacheFilled.addFilePaths(FilePathViews{"/path/to/file.cpp"}); +} + +TEST_F(FilePathCache, UseTransactionIfAddingFilesOnlyInAddFilePathsCalls) +{ + Cache cacheFilled{mockStorageFilled}; + InSequence s; + + EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(mockStorageFilled, fetchDirectoryIdUnguarded(Eq("/path/to"))).Times(0); + EXPECT_CALL(mockStorageFilled, fetchSourceIdUnguarded(5, Eq("file.h"))); + EXPECT_CALL(mockDatabase, commit()); + + cacheFilled.addFilePaths(FilePathViews{"/path/to/file.h"}); +} } // namespace diff --git a/tests/unit/unittest/mockfilepathcaching.h b/tests/unit/unittest/mockfilepathcaching.h index ca7960513eb..bec249a5a53 100644 --- a/tests/unit/unittest/mockfilepathcaching.h +++ b/tests/unit/unittest/mockfilepathcaching.h @@ -42,5 +42,5 @@ public: Utils::PathString(ClangBackEnd::DirectoryPathId directoryPathId)); MOCK_CONST_METHOD1(directoryPathId, ClangBackEnd::DirectoryPathId(ClangBackEnd::FilePathId filePathId)); + MOCK_METHOD1(addFilePaths, void(const ClangBackEnd::FilePaths &filePaths)); }; - diff --git a/tests/unit/unittest/mockfilepathstorage.h b/tests/unit/unittest/mockfilepathstorage.h index c6701228e72..cc6cfa07c7b 100644 --- a/tests/unit/unittest/mockfilepathstorage.h +++ b/tests/unit/unittest/mockfilepathstorage.h @@ -27,13 +27,18 @@ #include "googletest.h" +#include "mocksqlitedatabase.h" + #include class MockFilePathStorage { public: - MOCK_METHOD1(fetchDirectoryId, - int (Utils::SmallStringView directoryPath)); + MockFilePathStorage(MockSqliteDatabase &mockDatabase) + : mockDatabase{mockDatabase} + {} + + MOCK_METHOD1(fetchDirectoryId, int(Utils::SmallStringView directoryPath)); MOCK_METHOD2(fetchSourceId, int (int directoryId, Utils::SmallStringView sourceName)); MOCK_METHOD1(fetchDirectoryIdUnguarded, int(Utils::SmallStringView directoryPath)); @@ -44,5 +49,9 @@ public: ClangBackEnd::Sources::SourceNameAndDirectoryId (int sourceId)); MOCK_METHOD0(fetchAllDirectories, std::vector()); MOCK_METHOD0(fetchAllSources, std::vector()); + + MockSqliteDatabase &database() { return mockDatabase; } + + MockSqliteDatabase &mockDatabase; }; diff --git a/tests/unit/unittest/projectupdater-test.cpp b/tests/unit/unittest/projectupdater-test.cpp index 88ba30dd8fc..73f5359df09 100644 --- a/tests/unit/unittest/projectupdater-test.cpp +++ b/tests/unit/unittest/projectupdater-test.cpp @@ -25,6 +25,7 @@ #include "googletest.h" +#include "mockfilepathcaching.h" #include "mockpchmanagerclient.h" #include "mockpchmanagernotifier.h" #include "mockpchmanagerserver.h" @@ -470,6 +471,22 @@ TEST_F(ProjectUpdater, FetchProjectPartName) ASSERT_THAT(projectPartName, Eq(QString{" projectb"})); } +TEST_F(ProjectUpdater, AddProjectFilesToFilePathCache) +{ + NiceMock mockFilePathCaching; + ClangPchManager::ProjectUpdater updater{mockPchManagerServer, + mockFilePathCaching, + projectPartsStorage}; + + EXPECT_CALL(mockFilePathCaching, + addFilePaths(UnorderedElementsAre(Eq(headerPaths[0]), + Eq(headerPaths[1]), + Eq(sourcePaths[0]), + Eq(sourcePaths[1])))); + + updater.updateProjectParts({&projectPart}, {}); +} + // test for update many time and get the same id } // namespace diff --git a/tests/unit/unittest/stringcache-test.cpp b/tests/unit/unittest/stringcache-test.cpp index 027adb2ac61..10dbb69aac3 100644 --- a/tests/unit/unittest/stringcache-test.cpp +++ b/tests/unit/unittest/stringcache-test.cpp @@ -25,8 +25,9 @@ #include "googletest.h" -#include "mockmutex.h" #include "mockfilepathstorage.h" +#include "mockmutex.h" +#include "mocksqlitedatabase.h" #include @@ -72,7 +73,8 @@ protected: } protected: - NiceMock mockStorage; + NiceMock mockDatabase; + NiceMock mockStorage{mockDatabase}; StorageIdFunction mockStorageFetchDirectyId = [&] (Utils::SmallStringView string) { return mockStorage.fetchDirectoryId(string); };