File indexing completed on 2024-04-28 07:40:09
0001 /* 0002 This file is part of the KDE Baloo project. 0003 SPDX-FileCopyrightText: 2011 Sebastian Trueg <trueg@kde.org> 0004 SPDX-FileCopyrightText: 2013-2014 Vishesh Handa <me@vhanda.in> 0005 0006 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0007 */ 0008 0009 #include "pendingfilequeue.h" 0010 0011 #include <memory> 0012 0013 #include <QDateTime> 0014 0015 using namespace Baloo; 0016 0017 PendingFileQueue::PendingFileQueue(QObject* parent) 0018 : QObject(parent) 0019 { 0020 m_cacheTimer.setInterval(10); 0021 m_cacheTimer.setSingleShot(true); 0022 connect(&m_cacheTimer, &QTimer::timeout, [this] { 0023 PendingFileQueue::processCache(QTime::currentTime()); 0024 }); 0025 0026 m_trackingTime = 120 * 1000; 0027 0028 m_clearRecentlyEmittedTimer.setInterval(m_trackingTime); 0029 m_clearRecentlyEmittedTimer.setSingleShot(true); 0030 connect(&m_clearRecentlyEmittedTimer, &QTimer::timeout, [this] { 0031 PendingFileQueue::clearRecentlyEmitted(QTime::currentTime()); 0032 }); 0033 0034 m_minTimeout = 5 * 1000; 0035 m_maxTimeout = 60 * 1000; 0036 m_pendingFilesTimer.setInterval(m_minTimeout); 0037 m_pendingFilesTimer.setSingleShot(true); 0038 connect(&m_pendingFilesTimer, &QTimer::timeout, [this] { 0039 PendingFileQueue::processPendingFiles(QTime::currentTime()); 0040 }); 0041 } 0042 0043 PendingFileQueue::~PendingFileQueue() 0044 { 0045 } 0046 0047 void PendingFileQueue::enqueue(const PendingFile& file) 0048 { 0049 // If we get an event to remove /home/A, remove all events for everything under /home/A/ 0050 0051 if (file.shouldRemoveIndex() && file.path().endsWith(QLatin1Char('/'))) { 0052 const auto keepFile = [&file](const PendingFile& pending) { 0053 return !pending.path().startsWith(file.path()); 0054 }; 0055 const auto end = m_cache.end(); 0056 // std::partition moves all matching entries to the first partition 0057 const auto droppedFilesBegin = std::partition(m_cache.begin(), end, keepFile); 0058 for (auto it = droppedFilesBegin; it != end; it++) { 0059 m_pendingFiles.remove(it->path()); 0060 m_recentlyEmitted.remove(it->path()); 0061 } 0062 m_cache.erase(droppedFilesBegin, end); 0063 } 0064 0065 if (file.shouldRemoveIndex()) { 0066 m_cache.removeOne(file); 0067 m_pendingFiles.remove(file.path()); 0068 Q_EMIT removeFileIndex(file.path()); 0069 return; 0070 } 0071 0072 int i = m_cache.indexOf(file); 0073 if (i == -1) { 0074 m_cache << file; 0075 } else { 0076 m_cache[i].merge(file); 0077 } 0078 0079 m_cacheTimer.start(); 0080 } 0081 0082 void PendingFileQueue::processCache(const QTime& currentTime) 0083 { 0084 for (const PendingFile& file : std::as_const(m_cache)) { 0085 if (file.shouldIndexXAttrOnly()) { 0086 Q_EMIT indexXAttr(file.path()); 0087 } 0088 else if (file.shouldIndexContents()) { 0089 if (m_pendingFiles.contains(file.path())) { 0090 QTime time = m_pendingFiles[file.path()]; 0091 0092 int msecondsLeft = currentTime.msecsTo(time); 0093 msecondsLeft = qBound(m_minTimeout, msecondsLeft * 2, m_maxTimeout); 0094 0095 time = currentTime.addMSecs(msecondsLeft); 0096 m_pendingFiles[file.path()] = time; 0097 } 0098 else if (m_recentlyEmitted.contains(file.path())) { 0099 QTime time = currentTime.addMSecs(m_minTimeout); 0100 m_pendingFiles[file.path()] = time; 0101 } 0102 else { 0103 if (file.isNewFile()) { 0104 Q_EMIT indexNewFile(file.path()); 0105 } else { 0106 Q_EMIT indexModifiedFile(file.path()); 0107 } 0108 m_recentlyEmitted.insert(file.path(), currentTime); 0109 } 0110 } else { 0111 Q_ASSERT_X(false, "FileWatch", "The PendingFile should always have some flags set"); 0112 } 0113 } 0114 0115 m_cache.clear(); 0116 0117 if (!m_pendingFiles.isEmpty() && !m_pendingFilesTimer.isActive()) { 0118 m_pendingFilesTimer.setInterval(m_minTimeout); 0119 m_pendingFilesTimer.start(); 0120 } 0121 0122 if (!m_recentlyEmitted.isEmpty() && !m_clearRecentlyEmittedTimer.isActive()) { 0123 m_clearRecentlyEmittedTimer.setInterval(m_trackingTime); 0124 m_clearRecentlyEmittedTimer.start(); 0125 } 0126 } 0127 0128 void PendingFileQueue::clearRecentlyEmitted(const QTime& time) 0129 { 0130 int nextUpdate = m_trackingTime; 0131 0132 QMutableHashIterator<QString, QTime> it(m_recentlyEmitted); 0133 while (it.hasNext()) { 0134 it.next(); 0135 0136 int msecondsSinceEmitted = it.value().msecsTo(time); 0137 if (msecondsSinceEmitted >= m_trackingTime) { 0138 it.remove(); 0139 } else { 0140 int timeLeft = m_trackingTime - msecondsSinceEmitted; 0141 nextUpdate = qMin(nextUpdate, timeLeft); 0142 } 0143 } 0144 0145 if (!m_recentlyEmitted.isEmpty()) { 0146 m_clearRecentlyEmittedTimer.setInterval(nextUpdate); 0147 m_clearRecentlyEmittedTimer.start(); 0148 } 0149 } 0150 0151 void PendingFileQueue::processPendingFiles(const QTime& currentTime) 0152 { 0153 int nextUpdate = m_maxTimeout; 0154 0155 QMutableHashIterator<QString, QTime> it(m_pendingFiles); 0156 while (it.hasNext()) { 0157 it.next(); 0158 0159 int mSecondsLeft = currentTime.msecsTo(it.value()); 0160 if (mSecondsLeft <= 0) { 0161 Q_EMIT indexModifiedFile(it.key()); 0162 m_recentlyEmitted.insert(it.key(), currentTime); 0163 0164 it.remove(); 0165 } 0166 else { 0167 nextUpdate = qMin(mSecondsLeft, nextUpdate); 0168 } 0169 } 0170 0171 if (!m_pendingFiles.isEmpty()) { 0172 m_pendingFilesTimer.setInterval(nextUpdate); 0173 m_pendingFilesTimer.start(); 0174 } 0175 0176 if (!m_recentlyEmitted.isEmpty() && !m_clearRecentlyEmittedTimer.isActive()) { 0177 m_clearRecentlyEmittedTimer.setInterval(m_trackingTime); 0178 m_clearRecentlyEmittedTimer.start(); 0179 } 0180 } 0181 0182 void PendingFileQueue::setTrackingTime(int seconds) 0183 { 0184 m_trackingTime = seconds * 1000; 0185 } 0186 0187 void PendingFileQueue::setMinimumTimeout(int seconds) 0188 { 0189 m_minTimeout = seconds * 1000; 0190 } 0191 0192 void PendingFileQueue::setMaximumTimeout(int seconds) 0193 { 0194 m_maxTimeout = seconds * 1000; 0195 } 0196 0197 #include "moc_pendingfilequeue.cpp"