File indexing completed on 2024-05-12 04:38:06
0001 /* 0002 SPDX-FileCopyrightText: 2008 David Nolden <david.nolden.kdevelop@art-master.de> 0003 0004 SPDX-License-Identifier: LGPL-2.0-only 0005 */ 0006 0007 #include "modificationrevision.h" 0008 0009 #include <QString> 0010 #include <QFileInfo> 0011 #include <QMutex> 0012 #include <QMutexLocker> 0013 0014 #include <serialization/indexedstring.h> 0015 #include "modificationrevisionset.h" 0016 0017 /// @todo Listen to filesystem changes (together with the project manager) 0018 /// and call fileModificationCache().clear(...) when a file has changed 0019 0020 const int KDevelop::cacheModificationTimesForSeconds = 30; 0021 0022 using namespace KDevelop; 0023 namespace 0024 { 0025 struct FileModificationCache 0026 { 0027 QDateTime m_readTime; 0028 QDateTime m_modificationTime; 0029 }; 0030 } 0031 Q_DECLARE_TYPEINFO(FileModificationCache, Q_MOVABLE_TYPE); 0032 0033 namespace 0034 { 0035 using FileModificationMap = QHash<IndexedString, FileModificationCache>; 0036 using OpenDocumentRevisionsMap = QHash<IndexedString, int>; 0037 0038 // data protected by the mutex in the StaticCacheData below 0039 struct CacheData { 0040 FileModificationMap fileModificationCache; 0041 OpenDocumentRevisionsMap openRevisionsCache; 0042 0043 QDateTime fileModificationTimeCached(const IndexedString& fileName) 0044 { 0045 const auto currentTime = QDateTime::currentDateTimeUtc(); 0046 0047 auto it = fileModificationCache.constFind(fileName); 0048 if (it != fileModificationCache.constEnd()) { 0049 /// Use the cache for X seconds 0050 if (it.value().m_readTime.secsTo(currentTime) < cacheModificationTimesForSeconds) { 0051 return it.value().m_modificationTime; 0052 } 0053 } 0054 0055 QFileInfo fileInfo(fileName.str()); 0056 FileModificationCache data = { currentTime, fileInfo.lastModified() }; 0057 fileModificationCache.insert(fileName, data); 0058 return data.m_modificationTime; 0059 } 0060 0061 ModificationRevision revisionForFile(const IndexedString& url) 0062 { 0063 ModificationRevision ret(fileModificationTimeCached(url)); 0064 0065 OpenDocumentRevisionsMap::const_iterator it = openRevisionsCache.constFind(url); 0066 if (it != openRevisionsCache.constEnd()) { 0067 ret.revision = it.value(); 0068 } 0069 0070 return ret; 0071 } 0072 }; 0073 0074 // protects CacheData with a mutex and only allows thread safe access 0075 class StaticCacheData 0076 { 0077 public: 0078 template <typename Op> 0079 auto op(Op&& op) 0080 { 0081 QMutexLocker lock(&m_mutex); 0082 return op(m_cacheData); 0083 } 0084 0085 private: 0086 QMutex m_mutex; 0087 CacheData m_cacheData; 0088 }; 0089 0090 StaticCacheData& cacheData() 0091 { 0092 static StaticCacheData cacheData; 0093 return cacheData; 0094 } 0095 } 0096 0097 void ModificationRevision::clearModificationCache(const IndexedString& fileName) 0098 { 0099 ///@todo Make the cache management more clever (don't clear the whole) 0100 ModificationRevisionSet::clearCache(); 0101 0102 cacheData().op([&fileName](CacheData& data) { data.fileModificationCache.remove(fileName); }); 0103 } 0104 0105 ModificationRevision ModificationRevision::revisionForFile(const IndexedString& url) 0106 { 0107 return cacheData().op([&url](CacheData& data) { return data.revisionForFile(url); }); 0108 } 0109 0110 void ModificationRevision::clearEditorRevisionForFile(const IndexedString& url) 0111 { 0112 ModificationRevisionSet::clearCache(); ///@todo Make the cache management more clever (don't clear the whole) 0113 0114 return cacheData().op([&url](CacheData& data) { data.openRevisionsCache.remove(url); }); 0115 } 0116 0117 void ModificationRevision::setEditorRevisionForFile(const IndexedString& url, int revision) 0118 { 0119 ModificationRevisionSet::clearCache(); ///@todo Make the cache management more clever (don't clear the whole) 0120 0121 return cacheData().op([&url, revision](CacheData& data) { 0122 data.openRevisionsCache.insert(url, revision); 0123 Q_ASSERT(data.revisionForFile(url).revision == revision); 0124 }); 0125 } 0126 0127 ModificationRevision::ModificationRevision(const QDateTime& modTime, int revision_) 0128 : modificationTime(modTime.toSecsSinceEpoch()) 0129 , revision(revision_) 0130 { 0131 } 0132 0133 bool ModificationRevision::operator <(const ModificationRevision& rhs) const 0134 { 0135 return modificationTime < rhs.modificationTime || 0136 (modificationTime == rhs.modificationTime && revision < rhs.revision); 0137 } 0138 0139 bool ModificationRevision::operator ==(const ModificationRevision& rhs) const 0140 { 0141 return modificationTime == rhs.modificationTime && revision == rhs.revision; 0142 } 0143 0144 bool ModificationRevision::operator !=(const ModificationRevision& rhs) const 0145 { 0146 return modificationTime != rhs.modificationTime || revision != rhs.revision; 0147 } 0148 0149 QString ModificationRevision::toString() const 0150 { 0151 return QStringLiteral("%1 (rev %2)").arg(QDateTime::fromSecsSinceEpoch(modificationTime, Qt::LocalTime).time().toString()).arg(revision); 0152 }