#
#
# add_file "src/util/LRUCache.h"
# content [bc4dc5c7b84b9353bd08d543bd0c2080188309fe]
#
# patch "guitone.pro"
# from [6f299c589c6eefae31cf4e612f0e021ebf104903]
# to [427722d346990785a3b3598c7bc49d40f606c179]
#
# patch "src/model/InventoryModel.cpp"
# from [6497e49ed857bcace63fa6191430ac4fffd956a6]
# to [b306a75c202e78afa1726f3706ed7363bb17debf]
#
# patch "src/model/InventoryWatcher.cpp"
# from [f84de58ddd0f6adb881e5c0cf36ed755dfcb718e]
# to [d0a2d88d832ccd43b95b15642a89fe2454171a38]
#
# patch "src/model/InventoryWatcher.h"
# from [1de9c4f05371358e6d73844c44f4c819ceb04e35]
# to [ae3f783cea8382a2592f58468a39a76f33b16036]
#
============================================================
--- src/util/LRUCache.h bc4dc5c7b84b9353bd08d543bd0c2080188309fe
+++ src/util/LRUCache.h bc4dc5c7b84b9353bd08d543bd0c2080188309fe
@@ -0,0 +1,107 @@
+/***************************************************************************
+ * Copyright (C) 2010 by Thomas Keller *
+ * address@hidden *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation, either version 3 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program. If not, see . *
+ ***************************************************************************/
+
+#ifndef LRU_CACHE_H
+#define LRU_CACHE_H
+
+#include "vocab.h"
+
+#include
+#include
+
+template
+class LRUCache
+{
+public:
+ LRUCache(int max)
+ {
+ I(max > 0);
+ maxItems = max;
+ }
+
+ T add(const T & key, int initial = 1, int update = 1)
+ {
+ T removed;
+ if (!contains(key))
+ {
+ if (size() == maxItems)
+ {
+ removed = removeOldest();
+ }
+ counter.insert(key, initial);
+ revCounter.insert(initial, key);
+ }
+ else
+ {
+ int oldHeat = counter.value(key);
+ counter[key] = oldHeat + update;
+ revCounter.remove(oldHeat, key);
+ revCounter.insert(oldHeat + update, key);
+ }
+ return removed;
+ }
+
+ void remove(const T & key)
+ {
+ if (!contains(key))
+ return;
+
+ int heat = counter.take(key);
+ I(revCounter.remove(heat, key) == 1);
+ }
+
+ T removeOldest()
+ {
+ // the keys already come in ascending order
+ QList keys = revCounter.uniqueKeys();
+ I(keys.size() > 0);
+
+ int heat = keys.at(0);
+
+ QList vals = revCounter.values(heat);
+ I(vals.size() > 0);
+
+ I(counter.remove(vals.last()) == 1);
+ I(revCounter.remove(heat, vals.last()) == 1);
+ return vals.last();
+ }
+
+ bool contains(const T & key) const
+ {
+ return counter.contains(key);
+ }
+
+ int size() const
+ {
+ return counter.size();
+ }
+
+ void clear()
+ {
+ counter.clear();
+ revCounter.clear();
+ }
+
+private:
+ int maxItems;
+ QMap counter;
+ QMultiMap revCounter;
+};
+
+#endif
+
============================================================
--- guitone.pro 6f299c589c6eefae31cf4e612f0e021ebf104903
+++ guitone.pro 427722d346990785a3b3598c7bc49d40f606c179
@@ -109,6 +109,7 @@ HEADERS = src/view/widgets/TreeView.h \
src/util/TreeBuilder.h \
src/util/DebugLog.h \
src/util/StdioParser.h \
+ src/util/LRUCache.h \
src/GuitoneCore.h \
src/GuitoneStandalone.h \
src/GuitoneDriver.h \
============================================================
--- src/model/InventoryModel.cpp 6497e49ed857bcace63fa6191430ac4fffd956a6
+++ src/model/InventoryModel.cpp b306a75c202e78afa1726f3706ed7363bb17debf
@@ -330,7 +330,10 @@ void InventoryModel::triggerEndInsertRow
if (invItem->getFSType() == InventoryItem::None) continue;
// a little optimization: we don't care about / monitor ignored files
if (invItem->hasStatus(InventoryItem::Ignored)) continue;
- paths.push_back(invItem->getPath());
+
+ QString path = invItem->getPath();
+ if (invItem->isDirectory()) path += "/";
+ paths.push_back(path);
}
delete insertion;
@@ -349,7 +352,10 @@ void InventoryModel::triggerBeginRemoveR
ModelItem * child = parent->child(i);
InventoryItem * invItem = qobject_cast(child);
if (!invItem) continue;
- paths.push_back(invItem->getPath());
+
+ QString path = invItem->getPath();
+ if (invItem->isDirectory()) path += "/";
+ paths.push_back(path);
}
emit pathsRemoved(paths);
============================================================
--- src/model/InventoryWatcher.cpp f84de58ddd0f6adb881e5c0cf36ed755dfcb718e
+++ src/model/InventoryWatcher.cpp d0a2d88d832ccd43b95b15642a89fe2454171a38
@@ -21,7 +21,9 @@ InventoryWatcher::InventoryWatcher(QObje
#include "BasicIOParser.h"
InventoryWatcher::InventoryWatcher(QObject * parent)
- : QFileSystemWatcher(parent)
+ : QFileSystemWatcher(parent),
+ // do not watch more than 200 paths at once
+ lruCache(200)
{
connect(
this, SIGNAL(directoryChanged(const QString &)),
@@ -72,9 +74,25 @@ void InventoryWatcher::watchPaths(const
foreach (const QString & path, paths)
{
QString fullPath(workspace);
- if (!path.isEmpty()) fullPath += "/" + path;
+ if (path != "/") fullPath += "/" + path;
if (watchedPaths.indexOf(fullPath) != -1) continue;
- addPath(fullPath);
+ D(QString("adding %1").arg(fullPath));
+ removePath(fullPath);
+
+ // directories end with a slash and should keep a little longer
+ // around, thats why we give them one additional heat point
+ // more initially
+ QString removedPath = lruCache.add(
+ path, path.right(1) == "/" ? 2 : 1, 1
+ );
+
+ if (!removedPath.isEmpty())
+ {
+ QString fullRemovedPath(workspace);
+ if (removedPath != "/") fullRemovedPath += "/" + removedPath;
+ D(QString("removing %1 because of LRU").arg(fullRemovedPath));
+ removePath(fullRemovedPath);
+ }
}
}
@@ -85,9 +103,10 @@ void InventoryWatcher::unwatchPaths(cons
foreach (const QString & path, paths)
{
QString fullPath(workspace);
- if (!path.isEmpty()) fullPath += "/" + path;
+ if (path != "/") fullPath += "/" + path;
if (watchedPaths.indexOf(fullPath) == -1) continue;
removePath(fullPath);
+ lruCache.remove(path);
}
}
@@ -104,12 +123,12 @@ void InventoryWatcher::pathChanged(const
return;
}
- addPathAndStartTimer(
+ markPathForNotification(
path.mid(path.indexOf(workspace) + workspace.length() + 1)
);
}
-void InventoryWatcher::addPathAndStartTimer(const QString & newPath)
+void InventoryWatcher::markPathForNotification(const QString & newPath)
{
//
// The following algorithm only picks those paths for an update
@@ -300,14 +319,14 @@ void InventoryWatcher::checkForBookkeepC
if (foundOrAlreadyHandled) continue;
- addPathAndStartTimer(newStanza.at(0).vals.at(0));
+ markPathForNotification(newStanza.at(0).vals.at(0));
}
// now loop through all the left old items;
// we should only have a subset of items in this list now
foreach (const Stanza & oldStanza, oldRevisionEntries)
{
- addPathAndStartTimer(oldStanza.at(0).vals.at(0));
+ markPathForNotification(oldStanza.at(0).vals.at(0));
}
oldRevisionEntries = newRevisionEntries;
@@ -319,5 +338,6 @@ void InventoryWatcher::clearAllWatches()
changedPaths.clear();
removePaths(directories());
removePaths(files());
+ lruCache.clear();
}
============================================================
--- src/model/InventoryWatcher.h 1de9c4f05371358e6d73844c44f4c819ceb04e35
+++ src/model/InventoryWatcher.h ae3f783cea8382a2592f58468a39a76f33b16036
@@ -20,6 +20,8 @@
#define INVENTORY_WATCHER_H
#include "vocab.h"
+#include "LRUCache.h"
+
#include
#include
#include
@@ -42,13 +44,14 @@ private:
void clearAllWatches();
private:
- void addPathAndStartTimer(const QString &);
+ void markPathForNotification(const QString &);
void checkForBookkeepChanges();
WorkspacePath workspace;
StanzaList oldRevisionEntries;
QStringList changedPaths;
QTimer * notifyTimer;
+ LRUCache lruCache;
private slots:
void pathChanged(const QString &);