diff options
author | Marco Bubke <marco.bubke@qt.io> | 2019-06-06 10:57:55 +0200 |
---|---|---|
committer | Marco Bubke <marco.bubke@qt.io> | 2019-06-27 12:31:52 +0000 |
commit | bbd58ca30b32f6015a5e7eb16884dfb9f6108f17 (patch) | |
tree | 8f50bd05c6953797a1f73c6938925742284b24bc /src | |
parent | 9d290fc68206ce8323c259aab099faba93f7ec83 (diff) |
Clang: Watch directories instead of files
Because there a limited resources to watch files we watch now directories.
So we need much less resources.
Change-Id: Iac558832e9521a7a1a67c5ea99b42ad1b0b5129c
Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
Diffstat (limited to 'src')
23 files changed, 782 insertions, 235 deletions
diff --git a/src/libs/clangsupport/clangpathwatcher.h b/src/libs/clangsupport/clangpathwatcher.h index dab52996c2..7a7d6ccfcf 100644 --- a/src/libs/clangsupport/clangpathwatcher.h +++ b/src/libs/clangsupport/clangpathwatcher.h @@ -1,4 +1,4 @@ -/**************************************************************************** +; /**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ @@ -27,71 +27,94 @@ #include "clangpathwatcherinterface.h" #include "clangpathwatchernotifier.h" -#include "changedfilepathcompressor.h" +#include "directorypathcompressor.h" #include "filepathcachinginterface.h" +#include "filesystem.h" #include "stringcache.h" +#include <utils/algorithm.h> + #include <QTimer> namespace ClangBackEnd { +template<class InputIt1, class InputIt2, class Callable> +void set_greedy_intersection_call( + InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, Callable callable) +{ + while (first1 != last1 && first2 != last2) { + if (*first1 < *first2) { + ++first1; + } else { + if (*first2 < *first1) + ++first2; + else + callable(*first1++); + } + } +} + class WatcherEntry { public: ProjectPartId id; - FilePathId pathId; + DirectoryPathId directoryPathId; + FilePathId filePathId; + long long lastModified = -1; friend bool operator==(WatcherEntry first, WatcherEntry second) { - return first.id == second.id && first.pathId == second.pathId; + return first.id == second.id && first.directoryPathId == second.directoryPathId + && first.filePathId == second.filePathId; } friend bool operator<(WatcherEntry first, WatcherEntry second) { - return std::tie(first.pathId, first.id) < std::tie(second.pathId, second.id); + return std::tie(first.directoryPathId, first.filePathId, first.id) + < std::tie(second.directoryPathId, second.filePathId, second.id); } - friend bool operator<(WatcherEntry entry, FilePathId pathId) + friend bool operator<(DirectoryPathId directoryPathId, WatcherEntry entry) { - return entry.pathId < pathId; + return directoryPathId < entry.directoryPathId; } - friend bool operator<(FilePathId pathId, WatcherEntry entry) + friend bool operator<(WatcherEntry entry, DirectoryPathId directoryPathId) { - return pathId < entry.pathId; + return entry.directoryPathId < directoryPathId; } - operator FilePathId() const - { - return pathId; - } + operator FilePathId() const { return filePathId; } + + operator DirectoryPathId() const { return directoryPathId; } }; using WatcherEntries = std::vector<WatcherEntry>; -template <typename FileSystemWatcher, - typename Timer> +template<typename FileSystemWatcher, typename Timer> class CLANGSUPPORT_GCCEXPORT ClangPathWatcher : public ClangPathWatcherInterface { public: ClangPathWatcher(FilePathCachingInterface &pathCache, - ClangPathWatcherNotifier *notifier=nullptr) - : m_changedFilePathCompressor(pathCache), - m_pathCache(pathCache), - m_notifier(notifier) + FileSystemInterface &fileSystem, + ClangPathWatcherNotifier *notifier = nullptr) + : m_pathCache(pathCache) + , m_fileStatusCache(fileSystem) + , m_fileSystem(fileSystem) + , m_notifier(notifier) { QObject::connect(&m_fileSystemWatcher, - &FileSystemWatcher::fileChanged, - [&] (const QString &filePath) { compressChangedFilePath(filePath); }); + &FileSystemWatcher::directoryChanged, + [&](const QString &path) { compressChangedDirectoryPath(path); }); - m_changedFilePathCompressor.setCallback([&] (ClangBackEnd::FilePathIds &&filePathIds) { - addChangedPathForFilePath(std::move(filePathIds)); + m_directoryPathCompressor.setCallback([&](ClangBackEnd::DirectoryPathIds &&directoryPathIds) { + addChangedPathForFilePath(std::move(directoryPathIds)); }); } ~ClangPathWatcher() { - m_changedFilePathCompressor.setCallback([&] (FilePathIds &&) {}); + m_directoryPathCompressor.setCallback([&](DirectoryPathIds &&) {}); } void updateIdPaths(const std::vector<IdPaths> &idPaths) override @@ -109,7 +132,7 @@ public: auto filteredPaths = filterNotWatchedPaths(removedEntries); if (!filteredPaths.empty()) - m_fileSystemWatcher.removePaths(convertWatcherEntriesToQStringList(filteredPaths)); + m_fileSystemWatcher.removePaths(convertWatcherEntriesToDirectoryPathList(filteredPaths)); } void setNotifier(ClangPathWatcherNotifier *notifier) override @@ -164,7 +187,13 @@ public: outputIterator = std::transform(idPath.filePathIds.begin(), idPath.filePathIds.end(), outputIterator, - [&] (FilePathId pathId) { return WatcherEntry{id, pathId}; }); + [&](FilePathId filePathId) { + return WatcherEntry{ + id, + m_pathCache.directoryPathId(filePathId), + filePathId, + m_fileStatusCache.lastModifiedTime(filePathId)}; + }); } std::sort(entries.begin(), entries.end()); @@ -182,7 +211,7 @@ public: mergeToWatchedEntries(newEntries); if (!filteredPaths.empty()) - m_fileSystemWatcher.addPaths(convertWatcherEntriesToQStringList(filteredPaths)); + m_fileSystemWatcher.addPaths(convertWatcherEntriesToDirectoryPathList(filteredPaths)); } void removeUnusedEntries(const WatcherEntries &entries, const ProjectPartIds &ids) @@ -194,33 +223,31 @@ public: auto filteredPaths = filterNotWatchedPaths(oldEntries); if (!filteredPaths.empty()) - m_fileSystemWatcher.removePaths(convertWatcherEntriesToQStringList(filteredPaths)); + m_fileSystemWatcher.removePaths(convertWatcherEntriesToDirectoryPathList(filteredPaths)); } - FileSystemWatcher &fileSystemWatcher() + FileSystemWatcher &fileSystemWatcher() { return m_fileSystemWatcher; } + + QStringList convertWatcherEntriesToDirectoryPathList(const DirectoryPathIds &directoryPathIds) const { - return m_fileSystemWatcher; + return Utils::transform<QStringList>(directoryPathIds, [&](DirectoryPathId id) { + return QString(m_pathCache.directoryPath(id)); + }); } - QStringList convertWatcherEntriesToQStringList( - const WatcherEntries &watcherEntries) + QStringList convertWatcherEntriesToDirectoryPathList(const WatcherEntries &watcherEntries) const { - QStringList paths; - paths.reserve(int(watcherEntries.size())); + DirectoryPathIds directoryPathIds = Utils::transform<DirectoryPathIds>( + watcherEntries, [&](WatcherEntry entry) { return entry.directoryPathId; }); - std::transform(watcherEntries.begin(), - watcherEntries.end(), - std::back_inserter(paths), - [&] (WatcherEntry entry) { - return QString(m_pathCache.filePath(entry.pathId).path()); - }); + std::sort(directoryPathIds.begin(), directoryPathIds.end()); + directoryPathIds.erase(std::unique(directoryPathIds.begin(), directoryPathIds.end()), + directoryPathIds.end()); - return paths; + return convertWatcherEntriesToDirectoryPathList(directoryPathIds); } - template <typename Compare> - WatcherEntries notWatchedEntries(const WatcherEntries &entries, - Compare compare) const + WatcherEntries notWatchedEntries(const WatcherEntries &entries) const { WatcherEntries notWatchedEntries; notWatchedEntries.reserve(entries.size()); @@ -229,24 +256,23 @@ public: entries.end(), m_watchedEntries.cbegin(), m_watchedEntries.cend(), - std::back_inserter(notWatchedEntries), - compare); + std::back_inserter(notWatchedEntries)); return notWatchedEntries; } - WatcherEntries notWatchedEntries(const WatcherEntries &entries) const + DirectoryPathIds notWatchedPaths(const DirectoryPathIds &ids) const { - return notWatchedEntries(entries, std::less<WatcherEntry>()); - } + DirectoryPathIds notWatchedDirectoryIds; + notWatchedDirectoryIds.reserve(ids.size()); - WatcherEntries notWatchedPaths(const WatcherEntries &entries) const - { - auto compare = [] (WatcherEntry first, WatcherEntry second) { - return first.pathId < second.pathId; - }; + std::set_difference(ids.begin(), + ids.end(), + m_watchedEntries.cbegin(), + m_watchedEntries.cend(), + std::back_inserter(notWatchedDirectoryIds)); - return notWatchedEntries(entries, compare); + return notWatchedDirectoryIds; } template <typename Compare> @@ -297,25 +323,24 @@ public: m_watchedEntries = std::move(newWatchedEntries); } - static - WatcherEntries uniquePaths(const WatcherEntries &pathEntries) + static DirectoryPathIds uniquePaths(const WatcherEntries &pathEntries) { - WatcherEntries uniqueEntries; - uniqueEntries.reserve(pathEntries.size()); + DirectoryPathIds uniqueDirectoryIds; + uniqueDirectoryIds.reserve(pathEntries.size()); - auto compare = [] (WatcherEntry first, WatcherEntry second) { - return first.pathId == second.pathId; + auto compare = [](WatcherEntry first, WatcherEntry second) { + return first.directoryPathId == second.directoryPathId; }; std::unique_copy(pathEntries.begin(), pathEntries.end(), - std::back_inserter(uniqueEntries), + std::back_inserter(uniqueDirectoryIds), compare); - return uniqueEntries; + return uniqueDirectoryIds; } - WatcherEntries filterNotWatchedPaths(const WatcherEntries &entries) + DirectoryPathIds filterNotWatchedPaths(const WatcherEntries &entries) const { return notWatchedPaths(uniquePaths(entries)); } @@ -351,40 +376,48 @@ public: oldEntries.end(), std::back_inserter(newWatchedEntries)); - - m_watchedEntries = newWatchedEntries; + m_watchedEntries = std::move(newWatchedEntries); } - void compressChangedFilePath(const QString &filePath) + void compressChangedDirectoryPath(const QString &path) { - m_changedFilePathCompressor.addFilePath(filePath); + m_directoryPathCompressor.addDirectoryPathId( + m_pathCache.directoryPathId(Utils::PathString{path})); } - WatcherEntries watchedEntriesForPaths(ClangBackEnd::FilePathIds &&filePathIds) + WatcherEntries watchedEntriesForPaths(ClangBackEnd::DirectoryPathIds &&directoryPathIds) { WatcherEntries foundEntries; - foundEntries.reserve(filePathIds.size()); - - for (FilePathId pathId : filePathIds) { - auto range = std::equal_range(m_watchedEntries.begin(), m_watchedEntries.end(), pathId); - foundEntries.insert(foundEntries.end(), range.first, range.second); - } + foundEntries.reserve(m_watchedEntries.size()); + + set_greedy_intersection_call(m_watchedEntries.begin(), + m_watchedEntries.end(), + directoryPathIds.begin(), + directoryPathIds.end(), + [&](WatcherEntry &entry) { + m_fileStatusCache.update(entry.filePathId); + auto currentLastModified = m_fileStatusCache.lastModifiedTime( + entry.filePathId); + if (entry.lastModified < currentLastModified) { + foundEntries.push_back(entry); + entry.lastModified = currentLastModified; + } + }); return foundEntries; } - FilePathIds watchedPaths(const FilePathIds &filePathIds) const + FilePathIds watchedPaths(const WatcherEntries &entries) const { - FilePathIds watchedFilePathIds; - watchedFilePathIds.reserve(filePathIds.size()); + auto filePathIds = Utils::transform<FilePathIds>(entries, [](WatcherEntry entry) { + return entry.filePathId; + }); + + std::sort(filePathIds.begin(), filePathIds.end()); - std::set_intersection(m_watchedEntries.begin(), - m_watchedEntries.end(), - filePathIds.begin(), - filePathIds.end(), - std::back_inserter(watchedFilePathIds)); + filePathIds.erase(std::unique(filePathIds.begin(), filePathIds.end()), filePathIds.end()); - return watchedFilePathIds; + return filePathIds; } ProjectPartIds idsForWatcherEntries(const WatcherEntries &foundEntries) @@ -403,21 +436,20 @@ public: ProjectPartIds uniqueIds(ProjectPartIds &&ids) { std::sort(ids.begin(), ids.end()); - auto newEnd = std::unique(ids.begin(), ids.end()); - ids.erase(newEnd, ids.end()); + ids.erase(std::unique(ids.begin(), ids.end()), ids.end()); return std::move(ids); } - void addChangedPathForFilePath(FilePathIds &&filePathIds) + void addChangedPathForFilePath(DirectoryPathIds &&directoryPathIds) { if (m_notifier) { - WatcherEntries foundEntries = watchedEntriesForPaths(std::move(filePathIds)); + WatcherEntries foundEntries = watchedEntriesForPaths(std::move(directoryPathIds)); ProjectPartIds changedIds = idsForWatcherEntries(foundEntries); m_notifier->pathsWithIdsChanged(uniqueIds(std::move(changedIds))); - m_notifier->pathsChanged(watchedPaths(filePathIds)); + m_notifier->pathsChanged(watchedPaths(foundEntries)); } } @@ -428,10 +460,12 @@ public: private: WatcherEntries m_watchedEntries; - ChangedFilePathCompressor<Timer> m_changedFilePathCompressor; FileSystemWatcher m_fileSystemWatcher; + FileStatusCache m_fileStatusCache; + FileSystemInterface &m_fileSystem; FilePathCachingInterface &m_pathCache; ClangPathWatcherNotifier *m_notifier; + DirectoryPathCompressor<Timer> m_directoryPathCompressor; }; } // namespace ClangBackEnd diff --git a/src/libs/clangsupport/clangsupport-lib.pri b/src/libs/clangsupport/clangsupport-lib.pri index df537f5848..9b6bbdf3ee 100644 --- a/src/libs/clangsupport/clangsupport-lib.pri +++ b/src/libs/clangsupport/clangsupport-lib.pri @@ -18,6 +18,7 @@ SOURCES += \ $$PWD/clangcodemodelserverproxy.cpp \ $$PWD/alivemessage.cpp \ $$PWD/completionsmessage.cpp \ + $$PWD/filesystem.cpp \ $$PWD/requestcompletionsmessage.cpp \ $$PWD/echomessage.cpp \ $$PWD/endmessage.cpp \ @@ -87,7 +88,8 @@ SOURCES += \ $$PWD/removegeneratedfilesmessage.cpp \ $$PWD/generatedfiles.cpp \ $$PWD/projectpartartefact.cpp \ - $$PWD/projectpartcontainer.cpp + $$PWD/projectpartcontainer.cpp \ + $$PWD/filestatuscache.cpp HEADERS += \ $$PWD/cancelmessage.h \ @@ -109,7 +111,11 @@ HEADERS += \ $$PWD/alivemessage.h \ $$PWD/clangsupportexceptions.h \ $$PWD/completionsmessage.h \ + $$PWD/directoryandfilepathid.h \ + $$PWD/directorypathid.h \ $$PWD/executeinloop.h \ + $$PWD/filesystem.h \ + $$PWD/filesysteminterface.h \ $$PWD/pchpaths.h \ $$PWD/projectpartid.h \ $$PWD/projectpartsstorage.h \ @@ -217,6 +223,8 @@ HEADERS += \ $$PWD/sourceentry.h \ $$PWD/modifiedtimecheckerinterface.h \ $$PWD/environment.h \ + $$PWD/filestatus.h \ + $$PWD/filestatuscache.h \ $$PWD/modifiedtimechecker.h contains(QT_CONFIG, reduce_exports):CONFIG += hide_symbols diff --git a/src/libs/clangsupport/directoryandfilepathid.h b/src/libs/clangsupport/directoryandfilepathid.h new file mode 100644 index 0000000000..8969372919 --- /dev/null +++ b/src/libs/clangsupport/directoryandfilepathid.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "directorypathid.h" +#include "filepathid.h" + +#include <QDataStream> + +#include <vector> + +namespace ClangBackEnd { +class DirectoryAndFilePathId +{ +public: + constexpr DirectoryAndFilePathId() = default; + + DirectoryAndFilePathId(const char *) = delete; + + DirectoryAndFilePathId(int directoryPathId, int filePathId) + : directoryPathId(directoryPathId) + , filePathId(filePathId) + {} + + bool isValid() const { return directoryPathId.isValid() && filePathId.isValid(); } + + friend bool operator==(DirectoryAndFilePathId first, DirectoryAndFilePathId second) + { + return first.isValid() && first.directoryPathId == second.directoryPathId + && first.filePathId == second.filePathId; + } + + friend bool operator!=(DirectoryAndFilePathId first, DirectoryAndFilePathId second) + { + return !(first == second); + } + + friend bool operator<(DirectoryAndFilePathId first, DirectoryAndFilePathId second) + { + return std::tie(first.directoryPathId, first.filePathId) + < std::tie(second.directoryPathId, second.filePathId); + } + + friend QDataStream &operator<<(QDataStream &out, + const DirectoryAndFilePathId &directoryAndFilePathId) + { + out << directoryAndFilePathId.directoryPathId; + out << directoryAndFilePathId.filePathId; + + return out; + } + + friend QDataStream &operator>>(QDataStream &in, DirectoryAndFilePathId &directoryAndFilePathId) + { + in >> directoryAndFilePathId.directoryPathId; + in >> directoryAndFilePathId.filePathId; + return in; + } + +public: + DirectoryPathId directoryPathId; + FilePathId filePathId; +}; + +using DirectoryAndFilePathIds = std::vector<DirectoryAndFilePathId>; + +} // namespace ClangBackEnd diff --git a/src/libs/clangsupport/changedfilepathcompressor.h b/src/libs/clangsupport/directorypathcompressor.h index aa8e1ec71a..cd02948e83 100644 --- a/src/libs/clangsupport/changedfilepathcompressor.h +++ b/src/libs/clangsupport/directorypathcompressor.h @@ -27,53 +27,44 @@ #include "clangsupport_global.h" -#include <filepathid.h> -#include <filepathcache.h> +#include "filepathcachinginterface.h" +#include <QDir> #include <QTimer> -#include <filepathcachinginterface.h> +#include <utils/algorithm.h> #include <functional> namespace ClangBackEnd { -template <typename Timer> -class ChangedFilePathCompressor +template<typename Timer> +class DirectoryPathCompressor { public: - ChangedFilePathCompressor(FilePathCachingInterface &filePathCache) - : m_filePathCache(filePathCache) - { - m_timer.setSingleShot(true); - } + DirectoryPathCompressor() { m_timer.setSingleShot(true); } - virtual ~ChangedFilePathCompressor() - { - } + virtual ~DirectoryPathCompressor() = default; - void addFilePath(const QString &filePath) + void addDirectoryPathId(DirectoryPathId directoryPathIdId) { - FilePathId filePathId = m_filePathCache.filePathId(FilePath(filePath)); + auto found = std::lower_bound(m_directoryPathIds.begin(), + m_directoryPathIds.end(), + directoryPathIdId); - auto found = std::lower_bound(m_filePaths.begin(), m_filePaths.end(), filePathId); - - if (found == m_filePaths.end() || *found != filePathId) - m_filePaths.insert(found, filePathId); + if (found == m_directoryPathIds.end() || *found != directoryPathIdId) + m_directoryPathIds.insert(found, directoryPathIdId); restartTimer(); } - FilePathIds takeFilePathIds() - { - return std::move(m_filePaths); - } + DirectoryPathIds takeDirectoryPathIds() { return std::move(m_directoryPathIds); } - virtual void setCallback(std::function<void(ClangBackEnd::FilePathIds &&)> &&callback) + virtual void setCallback(std::function<void(ClangBackEnd::DirectoryPathIds &&)> &&callback) { - QObject::connect(&m_timer, - &Timer::timeout, - [this, callback=std::move(callback)] { callback(takeFilePathIds()); }); + QObject::connect(&m_timer, &Timer::timeout, [this, callback = std::move(callback)] { + callback(takeDirectoryPathIds()); + }); } unittest_public: @@ -88,9 +79,8 @@ unittest_public: } private: - FilePathIds m_filePaths; + DirectoryPathIds m_directoryPathIds; Timer m_timer; - FilePathCachingInterface &m_filePathCache; }; } // namespace ClangBackEnd diff --git a/src/libs/clangsupport/directorypathid.h b/src/libs/clangsupport/directorypathid.h new file mode 100644 index 0000000000..2fd0b5847e --- /dev/null +++ b/src/libs/clangsupport/directorypathid.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include <QDataStream> + +#include <vector> + +namespace ClangBackEnd { +class DirectoryPathId +{ +public: + constexpr DirectoryPathId() = default; + + DirectoryPathId(const char *) = delete; + + DirectoryPathId(int directoryPathId) + : directoryPathId(directoryPathId) + {} + + bool isValid() const { return directoryPathId >= 0; } + + friend bool operator==(DirectoryPathId first, DirectoryPathId second) + { + return first.isValid() && first.directoryPathId == second.directoryPathId; + } + + friend bool operator!=(DirectoryPathId first, DirectoryPathId second) + { + return !(first == second); + } + + friend bool operator<(DirectoryPathId first, DirectoryPathId second) + { + return first.directoryPathId < second.directoryPathId; + } + + friend QDataStream &operator<<(QDataStream &out, const DirectoryPathId &directoryPathId) + { + out << directoryPathId.directoryPathId; + + return out; + } + + friend QDataStream &operator>>(QDataStream &in, DirectoryPathId &directoryPathId) + { + in >> directoryPathId.directoryPathId; + + return in; + } + +public: + int directoryPathId = -1; +}; + +using DirectoryPathIds = std::vector<DirectoryPathId>; + +} // namespace ClangBackEnd diff --git a/src/libs/clangsupport/filepathcache.h b/src/libs/clangsupport/filepathcache.h index bdd925a79c..4845416d22 100644 --- a/src/libs/clangsupport/filepathcache.h +++ b/src/libs/clangsupport/filepathcache.h @@ -25,9 +25,10 @@ #pragma once +#include "directorypathid.h" +#include "filepath.h" #include "filepathexceptions.h" #include "filepathid.h" -#include "filepath.h" #include "filepathview.h" #include "stringcache.h" @@ -121,10 +122,10 @@ public: { Utils::SmallStringView directoryPath = filePath.directory(); - int directoryId = m_directoryPathCache.stringId(directoryPath, - [&] (const Utils::SmallStringView) { - return m_filePathStorage.fetchDirectoryId(directoryPath); - }); + int directoryId = m_directoryPathCache.stringId( + directoryPath, [&](const Utils::SmallStringView directoryPath) { + return m_filePathStorage.fetchDirectoryId(directoryPath); + }); Utils::SmallStringView fileName = filePath.name(); @@ -136,6 +137,17 @@ public: return fileNameId; } + DirectoryPathId directoryPathId(Utils::SmallStringView directoryPath) const + { + Utils::SmallStringView path = directoryPath.back() == '/' + ? directoryPath.mid(0, directoryPath.size() - 1) + : directoryPath; + + return m_directoryPathCache.stringId(path, [&](const Utils::SmallStringView directoryPath) { + return m_filePathStorage.fetchDirectoryId(directoryPath); + }); + } + FilePath filePath(FilePathId filePathId) const { if (Q_UNLIKELY(!filePathId.isValid())) @@ -157,6 +169,32 @@ public: return FilePath{directoryPath, entry.fileName}; } + Utils::PathString directoryPath(DirectoryPathId directoryPathId) const + { + if (Q_UNLIKELY(!directoryPathId.isValid())) + throw NoDirectoryPathForInvalidDirectoryPathId(); + + auto fetchDirectoryPath = [&](int id) { return m_filePathStorage.fetchDirectoryPath(id); }; + + return m_directoryPathCache.string(directoryPathId.directoryPathId, fetchDirectoryPath); + } + + DirectoryPathId directoryPathId(FilePathId filePathId) const + { + if (Q_UNLIKELY(!filePathId.isValid())) + throw NoFilePathForInvalidFilePathId(); + + auto fetchSoureNameAndDirectoryId = [&](int id) { + auto entry = m_filePathStorage.fetchSourceNameAndDirectoryId(id); + return FileNameEntry{entry.sourceName, entry.directoryId}; + }; + + FileNameEntry entry = m_fileNameCache.string(filePathId.filePathId, + fetchSoureNameAndDirectoryId); + + return m_fileNameCache.string(filePathId.filePathId, fetchSoureNameAndDirectoryId).directoryId; + } + private: mutable DirectoryPathCache m_directoryPathCache; mutable FileNameCache m_fileNameCache; diff --git a/src/libs/clangsupport/filepathcaching.cpp b/src/libs/clangsupport/filepathcaching.cpp index 0a3fc6ee41..372ed86bd3 100644 --- a/src/libs/clangsupport/filepathcaching.cpp +++ b/src/libs/clangsupport/filepathcaching.cpp @@ -37,4 +37,19 @@ FilePath FilePathCaching::filePath(FilePathId filePathId) const return m_cache.filePath(filePathId); } +DirectoryPathId FilePathCaching::directoryPathId(Utils::SmallStringView directoryPath) const +{ + return m_cache.directoryPathId(directoryPath); +} + +Utils::PathString FilePathCaching::directoryPath(DirectoryPathId directoryPathId) const +{ + return m_cache.directoryPath(directoryPathId); +} + +DirectoryPathId FilePathCaching::directoryPathId(FilePathId filePathId) const +{ + return m_cache.directoryPathId(filePathId); +} + } // namespace ClangBackEnd diff --git a/src/libs/clangsupport/filepathcaching.h b/src/libs/clangsupport/filepathcaching.h index a3337755fd..f69b940b15 100644 --- a/src/libs/clangsupport/filepathcaching.h +++ b/src/libs/clangsupport/filepathcaching.h @@ -50,6 +50,9 @@ public: FilePathId filePathId(FilePathView filePath) const override; FilePath filePath(FilePathId filePathId) const override; + DirectoryPathId directoryPathId(Utils::SmallStringView directoryPath) const override; + Utils::PathString directoryPath(DirectoryPathId directoryPathId) const override; + DirectoryPathId directoryPathId(FilePathId filePathId) const override; private: Factory m_factory; diff --git a/src/libs/clangsupport/filepathcachinginterface.h b/src/libs/clangsupport/filepathcachinginterface.h index b9668362f7..098fd39ca9 100644 --- a/src/libs/clangsupport/filepathcachinginterface.h +++ b/src/libs/clangsupport/filepathcachinginterface.h @@ -25,6 +25,7 @@ #pragma once +#include "directorypathid.h" #include "filepath.h" #include "filepathid.h" #include "filepathview.h" @@ -40,8 +41,11 @@ public: virtual FilePathId filePathId(FilePathView filePath) const = 0; virtual FilePath filePath(FilePathId filePathId) const = 0; + virtual DirectoryPathId directoryPathId(Utils::SmallStringView directoryPath) const = 0; + virtual DirectoryPathId directoryPathId(FilePathId filePathId) const = 0; + virtual Utils::PathString directoryPath(DirectoryPathId directoryPathId) const = 0; - template <typename Container> + template<typename Container> FilePathIds filePathIds(Container &&filePaths) const { FilePathIds filePathIds; diff --git a/src/libs/clangsupport/filepathexceptions.h b/src/libs/clangsupport/filepathexceptions.h index 80bded0c66..3174d89479 100644 --- a/src/libs/clangsupport/filepathexceptions.h +++ b/src/libs/clangsupport/filepathexceptions.h @@ -38,6 +38,15 @@ public: } }; +class NoDirectoryPathForInvalidDirectoryPathId : std::exception +{ +public: + const char *what() const noexcept override + { + return "You cannot get a directory path for an invalid directory path id!"; + } +}; + class SourceNameIdDoesNotExists : std::exception { public: diff --git a/src/libs/clangsupport/filepathstorage.h b/src/libs/clangsupport/filepathstorage.h index 5917504dbf..8aba2ef6d2 100644 --- a/src/libs/clangsupport/filepathstorage.h +++ b/src/libs/clangsupport/filepathstorage.h @@ -179,12 +179,32 @@ public: transaction.commit(); - return optionalSourceName.value(); + return *optionalSourceName; } catch (const Sqlite::StatementIsBusy &) { return fetchSourceNameAndDirectoryId(sourceId); } } + int fetchDirectoryId(int sourceId) + { + try { + Sqlite::DeferredTransaction transaction{m_statementFactory.database}; + + ReadStatement &statement = m_statementFactory.selectDirectoryIdFromSourcesBySourceId; + + auto optionalDirectoryId = statement.template value<int>(sourceId); + + if (!optionalDirectoryId) + throw SourceNameIdDoesNotExists(); + + transaction.commit(); + + return *optionalDirectoryId; + } catch (const Sqlite::StatementIsBusy &) { + return fetchDirectoryId(sourceId); + } + } + std::vector<Sources::Source> fetchAllSources() { try { diff --git a/src/libs/clangsupport/filepathstoragesqlitestatementfactory.h b/src/libs/clangsupport/filepathstoragesqlitestatementfactory.h index dbf8071775..27296a1df6 100644 --- a/src/libs/clangsupport/filepathstoragesqlitestatementfactory.h +++ b/src/libs/clangsupport/filepathstoragesqlitestatementfactory.h @@ -69,6 +69,8 @@ public: "SELECT sourceName, directoryId FROM sources WHERE sourceId = ?", database }; + ReadStatement selectDirectoryIdFromSourcesBySourceId{ + "SELECT directoryId FROM sources WHERE sourceId = ?", database}; WriteStatement insertIntoSources{ "INSERT INTO sources(directoryId, sourceName) VALUES (?,?)", database diff --git a/src/tools/clangrefactoringbackend/source/filestatus.h b/src/libs/clangsupport/filestatus.h index da2be4a304..da2be4a304 100644 --- a/src/tools/clangrefactoringbackend/source/filestatus.h +++ b/src/libs/clangsupport/filestatus.h diff --git a/src/libs/clangsupport/filestatuscache.cpp b/src/libs/clangsupport/filestatuscache.cpp new file mode 100644 index 0000000000..480b745525 --- /dev/null +++ b/src/libs/clangsupport/filestatuscache.cpp @@ -0,0 +1,169 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "filestatuscache.h" +#include "filesystem.h" + +#include <utils/algorithm.h> + +#include <QDateTime> +#include <QFileInfo> + +namespace ClangBackEnd { + +long long FileStatusCache::lastModifiedTime(FilePathId filePathId) const +{ + return findEntry(filePathId).lastModified; +} + +void FileStatusCache::update(FilePathId filePathId) +{ + auto found = std::lower_bound(m_cacheEntries.begin(), + m_cacheEntries.end(), + Internal::FileStatusCacheEntry{filePathId}, + [] (const auto &first, const auto &second) { + return first.filePathId < second.filePathId; + }); + + if (found != m_cacheEntries.end() && found->filePathId == filePathId) + found->lastModified = m_fileSystem.lastModified(filePathId); +} + +namespace { +template<class InputIt1, class InputIt2, class Callable> +void set_intersection_call(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, Callable callable) +{ + while (first1 != last1 && first2 != last2) { + if (*first1 < *first2) { + ++first1; + } else { + if (!(*first2 < *first1)) + callable(*first1++); + ++first2; + } + } +} + +template<class InputIt1, class InputIt2, class Callable> +void set_difference_call(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, Callable callable) +{ + while (first1 != last1) { + if (first2 == last2) { + std::for_each(first1, last1, callable); + return; + } + if (*first1 < *first2) { + callable(*first1++); + } else { + if (!(*first2 < *first1)) + ++first1; + ++first2; + } + } +} +} // namespace + +void FileStatusCache::update(FilePathIds filePathIds) +{ + set_intersection_call(m_cacheEntries.begin(), + m_cacheEntries.end(), + filePathIds.begin(), + filePathIds.end(), + [&](auto &entry) { + entry.lastModified = m_fileSystem.lastModified(entry.filePathId); + }); +} + +FilePathIds FileStatusCache::modified(FilePathIds filePathIds) const +{ + FilePathIds modifiedFilePathIds; + modifiedFilePathIds.reserve(filePathIds.size()); + + set_intersection_call(m_cacheEntries.begin(), + m_cacheEntries.end(), + filePathIds.begin(), + filePathIds.end(), + [&](auto &entry) { + auto newLastModified = m_fileSystem.lastModified(entry.filePathId); + if (newLastModified > entry.lastModified) { + modifiedFilePathIds.push_back(entry.filePathId); + entry.lastModified = newLastModified; + } + }); + + Internal::FileStatusCacheEntries newEntries; + newEntries.reserve(filePathIds.size()); + + set_difference_call(filePathIds.begin(), + filePathIds.end(), + m_cacheEntries.begin(), + m_cacheEntries.end(), + [&](FilePathId newFilePathId) { + newEntries.emplace_back(newFilePathId, + m_fileSystem.lastModified(newFilePathId)); + modifiedFilePathIds.push_back(newFilePathId); + }); + + if (newEntries.size()) { + Internal::FileStatusCacheEntries mergedEntries; + mergedEntries.reserve(m_cacheEntries.size() + newEntries.size()); + + std::set_union(newEntries.begin(), + newEntries.end(), + m_cacheEntries.begin(), + m_cacheEntries.end(), + std::back_inserter(mergedEntries)); + + m_cacheEntries = std::move(mergedEntries); + } + + std::sort(modifiedFilePathIds.begin(), modifiedFilePathIds.end()); + + return modifiedFilePathIds; +} + +FileStatusCache::size_type FileStatusCache::size() const +{ + return m_cacheEntries.size(); +} + +Internal::FileStatusCacheEntry FileStatusCache::findEntry(FilePathId filePathId) const +{ + auto found = std::lower_bound(m_cacheEntries.begin(), + m_cacheEntries.end(), + Internal::FileStatusCacheEntry{filePathId}, + [] (const auto &first, const auto &second) { + return first.filePathId < second.filePathId; + }); + + if (found != m_cacheEntries.end() && found->filePathId == filePathId) + return *found; + + auto inserted = m_cacheEntries.emplace(found, filePathId, m_fileSystem.lastModified(filePathId)); + + return *inserted; +} + +} // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/filestatuscache.h b/src/libs/clangsupport/filestatuscache.h index 23195da605..3f0af56b3a 100644 --- a/src/tools/clangrefactoringbackend/source/filestatuscache.h +++ b/src/libs/clangsupport/filestatuscache.h @@ -31,6 +31,8 @@ QT_FORWARD_DECLARE_CLASS(QFileInfo) namespace ClangBackEnd { +class FileSystemInterface; + namespace Internal { class FileStatusCacheEntry { @@ -41,8 +43,23 @@ public: lastModified(lastModified) {} + friend bool operator<(FileStatusCacheEntry first, FileStatusCacheEntry second) + { + return first.filePathId < second.filePathId; + } + + friend bool operator<(FileStatusCacheEntry first, FilePathId second) + { + return first.filePathId < second; + } + + friend bool operator<(FilePathId first, FileStatusCacheEntry second) + { + return first < second.filePathId; + } + public: - ClangBackEnd::FilePathId filePathId; + FilePathId filePathId; long long lastModified; }; @@ -50,27 +67,30 @@ using FileStatusCacheEntries = std::vector<FileStatusCacheEntry>; } -class FileStatusCache +class CLANGSUPPORT_EXPORT FileStatusCache { public: using size_type = Internal::FileStatusCacheEntries::size_type; - FileStatusCache(FilePathCachingInterface &filePathCache); + FileStatusCache(FileSystemInterface &fileSystem) + : m_fileSystem(fileSystem) + {} FileStatusCache &operator=(const FileStatusCache &) = delete; FileStatusCache(const FileStatusCache &) = delete; - long long lastModifiedTime(ClangBackEnd::FilePathId filePathId) const; - void update(ClangBackEnd::FilePathId filePathId); + long long lastModifiedTime(FilePathId filePathId) const; + void update(FilePathId filePathId); + void update(FilePathIds filePathIds); + FilePathIds modified(FilePathIds filePathIds) const; size_type size() const; private: - Internal::FileStatusCacheEntry findEntry(ClangBackEnd::FilePathId filePathId) const; - QFileInfo qFileInfo(ClangBackEnd::FilePathId filePathId) const; + Internal::FileStatusCacheEntry findEntry(FilePathId filePathId) const; private: mutable Internal::FileStatusCacheEntries m_cacheEntries; - FilePathCachingInterface &m_filePathCache; + FileSystemInterface &m_fileSystem; }; } // namespace ClangBackEnd diff --git a/src/libs/clangsupport/filesystem.cpp b/src/libs/clangsupport/filesystem.cpp new file mode 100644 index 0000000000..5b8c037f80 --- /dev/null +++ b/src/libs/clangsupport/filesystem.cpp @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "filesystem.h" +#include "filepathcachinginterface.h" + +#include <utils/algorithm.h> + +#include <QDateTime> +#include <QDir> +#include <QFileInfo> + +namespace ClangBackEnd { + +FilePathIds FileSystem::directoryEntries(const QString &directoryPath) const +{ + QDir directory{directoryPath}; + + QFileInfoList fileInfos = directory.entryInfoList(); + + FilePathIds filePathIds = Utils::transform<FilePathIds>(fileInfos, [&](const QFileInfo &fileInfo) { + return m_filePathCache.filePathId(FilePath{fileInfo.path()}); + }); + + std::sort(filePathIds.begin(), filePathIds.end()); + + return filePathIds; +} + +long long FileSystem::lastModified(FilePathId filePathId) const +{ + QFileInfo fileInfo(QString(m_filePathCache.filePath(filePathId))); + + fileInfo.refresh(); + + return fileInfo.lastModified().toMSecsSinceEpoch() / 1000; +} + +} // namespace ClangBackEnd diff --git a/src/libs/clangsupport/filesystem.h b/src/libs/clangsupport/filesystem.h new file mode 100644 index 0000000000..ecf332de55 --- /dev/null +++ b/src/libs/clangsupport/filesystem.h @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "filestatuscache.h" +#include "filesysteminterface.h" + +namespace ClangBackEnd { +class FilePathCachingInterface; + +class CLANGSUPPORT_EXPORT FileSystem final : public FileSystemInterface +{ +public: + FileSystem(FilePathCachingInterface &filePathCache) + : m_filePathCache(filePathCache) + {} + + FilePathIds directoryEntries(const QString &directoryPath) const override; + long long lastModified(FilePathId filePathId) const override; + +private: + FilePathCachingInterface &m_filePathCache; +}; + +} // namespace ClangBackEnd diff --git a/src/libs/clangsupport/filesysteminterface.h b/src/libs/clangsupport/filesysteminterface.h new file mode 100644 index 0000000000..9d64d2a93a --- /dev/null +++ b/src/libs/clangsupport/filesysteminterface.h @@ -0,0 +1,43 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "filepathid.h" + +#include <utils/smallstringview.h> + +namespace ClangBackEnd { + +class FileSystemInterface +{ +public: + virtual FilePathIds directoryEntries(const QString &directoryPath) const = 0; + virtual long long lastModified(FilePathId filePathId) const = 0; + +protected: + ~FileSystemInterface() = default; +}; +} // namespace ClangBackEnd diff --git a/src/libs/utils/smallstringview.h b/src/libs/utils/smallstringview.h index 6052ff8777..911ba2eafd 100644 --- a/src/libs/utils/smallstringview.h +++ b/src/libs/utils/smallstringview.h @@ -179,6 +179,10 @@ public: return m_pointer[0] == characterToSearch; } + char back() const { return m_pointer[m_size - 1]; } + + char operator[](std::size_t index) { return m_pointer[index]; } + private: const char *m_pointer = ""; size_type m_size = 0; diff --git a/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp b/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp index 0ce49e829d..d9e7dd3175 100644 --- a/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp +++ b/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp @@ -31,6 +31,7 @@ #include <environment.h> #include <executeinloop.h> #include <filepathcaching.h> +#include <filesystem.h> #include <generatedfiles.h> #include <modifiedtimechecker.h> #include <pchcreator.h> @@ -179,7 +180,8 @@ struct Data // because we have a cycle dependency Sqlite::Database database; ClangBackEnd::RefactoringDatabaseInitializer<Sqlite::Database> databaseInitializer{database}; ClangBackEnd::FilePathCaching filePathCache{database}; - ClangPathWatcher<QFileSystemWatcher, QTimer> includeWatcher{filePathCache}; + ClangBackEnd::FileSystem fileSystem{filePathCache}; + ClangPathWatcher<QFileSystemWatcher, QTimer> includeWatcher{filePathCache, fileSystem}; ApplicationEnvironment environment; ProjectPartsStorage<> projectPartsStorage{database}; PrecompiledHeaderStorage<> preCompiledHeaderStorage{database}; diff --git a/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri b/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri index e7e83da788..a3da84d83b 100644 --- a/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri +++ b/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri @@ -17,8 +17,6 @@ HEADERS += \ $$PWD/symbolsvisitorbase.h \ $$PWD/usedmacro.h \ $$PWD/sourcedependency.h \ - $$PWD/filestatus.h \ - $$PWD/filestatuscache.h \ $$PWD/indexdataconsumer.h \ $$PWD/sourcesmanager.h \ $$PWD/symbolindexertaskqueue.h \ @@ -67,5 +65,4 @@ HEADERS += \ SOURCES += \ $$PWD/filestatuspreprocessorcallbacks.cpp \ $$PWD/sourcerangefilter.cpp \ - $$PWD/symbolindexer.cpp \ - $$PWD/filestatuscache.cpp + $$PWD/symbolindexer.cpp diff --git a/src/tools/clangrefactoringbackend/source/filestatuscache.cpp b/src/tools/clangrefactoringbackend/source/filestatuscache.cpp deleted file mode 100644 index 14ad48da14..0000000000 --- a/src/tools/clangrefactoringbackend/source/filestatuscache.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#include "filestatuscache.h" - -#include <QDateTime> -#include <QFileInfo> - -namespace ClangBackEnd { - -FileStatusCache::FileStatusCache(FilePathCachingInterface &filePathCache) - : m_filePathCache(filePathCache) -{ - -} - -long long FileStatusCache::lastModifiedTime(FilePathId filePathId) const -{ - return findEntry(filePathId).lastModified; -} - -void FileStatusCache::update(FilePathId filePathId) -{ - auto found = std::lower_bound(m_cacheEntries.begin(), - m_cacheEntries.end(), - Internal::FileStatusCacheEntry{filePathId}, - [] (const auto &first, const auto &second) { - return first.filePathId < second.filePathId; - }); - - if (found != m_cacheEntries.end() && found->filePathId == filePathId) { - QFileInfo fileInfo = qFileInfo(filePathId); - found->lastModified = fileInfo.lastModified().toMSecsSinceEpoch() / 1000; - } -} - -FileStatusCache::size_type FileStatusCache::size() const -{ - return m_cacheEntries.size(); -} - -Internal::FileStatusCacheEntry FileStatusCache::findEntry(FilePathId filePathId) const -{ - auto found = std::lower_bound(m_cacheEntries.begin(), - m_cacheEntries.end(), - Internal::FileStatusCacheEntry{filePathId}, - [] (const auto &first, const auto &second) { - return first.filePathId < second.filePathId; - }); - - if (found != m_cacheEntries.end() && found->filePathId == filePathId) - return *found; - - QFileInfo fileInfo = qFileInfo(filePathId); - auto inserted = m_cacheEntries.emplace(found, - filePathId, - fileInfo.lastModified().toMSecsSinceEpoch() / 1000); - - return *inserted; -} - -QFileInfo FileStatusCache::qFileInfo(FilePathId filePathId) const -{ - QFileInfo fileInfo(QString(m_filePathCache.filePath(filePathId))); - - fileInfo.refresh(); - - return fileInfo; -} - -} // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/symbolindexing.h b/src/tools/clangrefactoringbackend/source/symbolindexing.h index 5c391503bf..bed279904d 100644 --- a/src/tools/clangrefactoringbackend/source/symbolindexing.h +++ b/src/tools/clangrefactoringbackend/source/symbolindexing.h @@ -39,6 +39,7 @@ #include <projectpartsstorage.h> #include <filepathcachingfwd.h> +#include <filesystem.h> #include <modifiedtimechecker.h> #include <refactoringdatabaseinitializer.h> @@ -142,8 +143,9 @@ private: PrecompiledHeaderStorage<Sqlite::Database> m_precompiledHeaderStorage; ProjectPartsStorage<Sqlite::Database> m_projectPartsStorage; SymbolStorage m_symbolStorage; - ClangPathWatcher<QFileSystemWatcher, QTimer> m_sourceWatcher{m_filePathCache}; - FileStatusCache m_fileStatusCache{m_filePathCache}; + FileSystem m_fileSytem{m_filePathCache}; + ClangPathWatcher<QFileSystemWatcher, QTimer> m_sourceWatcher{m_filePathCache, m_fileSytem}; + FileStatusCache m_fileStatusCache{m_fileSytem}; SymbolsCollectorManager m_collectorManger; ProgressCounter m_progressCounter; std::function<TimeStamp(FilePathView filePath)> getModifiedTime{ |