Hi.
*
BUG :*
I was going through the Strigi Service, and I noticed that it stores the
folders to index in a service file named strigiservicerc (duh!) The problem
is that the folder being watched are sometimes renamed/moved, and when that
happens Strigi deletes its indexed metadata. Furthermore, if a directory in
one of the indexed directories, and is moved out of it, the metadata is
deleted. :-/ This all happens when the strigiservice is restarted. The
culprit -> Nepomuk::IndexScheduler::removeOldAndUnwantedEntries()
Fixing this, in my opinion, would require us to watch the indexed
directories for changes. Unfortunately crappy *inotify* doesn't allow this.
If a watched directory is renamed it gives us a EventMoveSelf, but doesn't
tell us what it has been renamed to or where it has been moved. (I know!
Stupid!) So, the only solution I can think of is to watch its parent
directory, that will atleast tell us what it's been renamed to. In order to
know where it has been moved to we'll need to watch everything, which is a
huge resource hog (Yes, Filewatcher, I'm talking about you!)
*
PATCHES :*
For starters, we need to move the kinotify class to a better location, so
that it can be used by both the filewatcher, and strigi.
In KINotify, I found a couple of functions to be implemented inefficiently (
O(n), when it can be close to O(1). ) So, I optimized it a little bit. The
problem came while optimizing *KInotify::removeWatch( const QString& path )*.
It currently removes all watches who's paths start with path, which doesn't
seem right. It should *only* remove the watch corresponding to the given
path. The full optimization patch does this.
I've tried to hack a solution to the *BUG*. This is just a preliminary
patch! I created a new class called ConfigFolderWatcher (got a better
name?). I didn't want to clutter up the *strigiservice* class. In order for
this class to work I copied the kinotify class from the filewatch service
(Temp. solution, you'll need to do the same) The current Patch works
perfectly for renaming and moving to a sibling directory. But not for, well,
anything else. Look at the source code! The filewatcher service suffers from
a somewhat same problem.
*
SCRIPTS :*
I usually tend to write scripts for stuff I do frequently, and I wrote a
couple for Nepomuk. They are available over here ->
http://pastebin.com/pxDVSWWQ . The service ones aren't perfect but they're
useful. Has anyone else written any scripts which may be useful? If so,
please share them! :-)
Thanks
- Vishesh Handa
Index: kinotify.cpp
===================================================================
--- kinotify.cpp (revision 1117887)
+++ kinotify.cpp (working copy)
@@ -67,6 +67,7 @@
QHash<int, QString> cookies;
QHash<int, QByteArray> pathHash;
+ QHash<QByteArray, int> reversePathHash;
/// queue of paths to install watches for
QQueue<QByteArray> pathsToWatch;
@@ -100,7 +101,9 @@
int wd = inotify_add_watch( inotify(), path.data(), mask );
if ( wd > 0 ) {
// kDebug() << "Successfully added watch for" << path << pathHash.count();
- pathHash.insert( wd, normalizePath( path ) );
+ QByteArray nPath = normalizePath( path );
+ pathHash.insert( wd, nPath );
+ reversePathHash.insert( nPath, wd );
return true;
}
else {
@@ -164,6 +167,7 @@
}
void removeWatch( int wd ) {
+ reversePathHash.remove( pathHash[ wd ] );
pathHash.remove( wd );
inotify_rm_watch( inotify(), wd );
}
@@ -244,13 +248,7 @@
bool KInotify::watchingPath( const QString& path ) const
{
QByteArray p( normalizePath( QFile::encodeName( path ) ) );
- QHash<int, QByteArray>::const_iterator end = d->pathHash.constEnd();
- for ( QHash<int, QByteArray>::const_iterator it = d->pathHash.constBegin();
- it != end; ++it ) {
- if ( it.value() == p )
- return true;
- }
- return false;
+ return d->reversePathHash.contains( p );
}
Index: kinotify.cpp
===================================================================
--- kinotify.cpp (revision 1117887)
+++ kinotify.cpp (working copy)
@@ -67,6 +67,7 @@
QHash<int, QString> cookies;
QHash<int, QByteArray> pathHash;
+ QHash<QByteArray, int> reversePathHash;
/// queue of paths to install watches for
QQueue<QByteArray> pathsToWatch;
@@ -100,7 +101,9 @@
int wd = inotify_add_watch( inotify(), path.data(), mask );
if ( wd > 0 ) {
// kDebug() << "Successfully added watch for" << path << pathHash.count();
- pathHash.insert( wd, normalizePath( path ) );
+ QByteArray nPath = normalizePath( path );
+ pathHash.insert( wd, nPath );
+ reversePathHash.insert( nPath, wd );
return true;
}
else {
@@ -164,6 +167,7 @@
}
void removeWatch( int wd ) {
+ reversePathHash.remove( pathHash[ wd ] );
pathHash.remove( wd );
inotify_rm_watch( inotify(), wd );
}
@@ -244,13 +248,7 @@
bool KInotify::watchingPath( const QString& path ) const
{
QByteArray p( normalizePath( QFile::encodeName( path ) ) );
- QHash<int, QByteArray>::const_iterator end = d->pathHash.constEnd();
- for ( QHash<int, QByteArray>::const_iterator it = d->pathHash.constBegin();
- it != end; ++it ) {
- if ( it.value() == p )
- return true;
- }
- return false;
+ return d->reversePathHash.contains( p );
}
@@ -266,21 +264,16 @@
}
-// TODO: do this more efficiently
bool KInotify::removeWatch( const QString& path )
{
- QByteArray encodedPath = QFile::encodeName( path );
- QHash<int, QByteArray>::iterator it = d->pathHash.begin();
- while ( it != d->pathHash.end() ) {
- if ( it.value().startsWith( encodedPath ) ) {
- inotify_rm_watch( d->inotify(), it.key() );
- it = d->pathHash.erase( it );
- }
- else {
- ++it;
- }
+ QByteArray p( normalizePath( QFile::encodeName( path ) ) );
+ if( d->reversePathHash.contains( p ) ) {
+ int wd = d->reversePathHash[ p ];
+ d->removeWatch( wd );
+
+ return true;
}
- return true;
+ return false;
}
Index: configfolderwatcher.cpp
===================================================================
--- configfolderwatcher.cpp (revision 0)
+++ configfolderwatcher.cpp (revision 0)
@@ -0,0 +1,148 @@
+#include "configfolderwatcher.h"
+#include "kinotify.h"
+#include "strigiserviceconfig.h"
+
+#include <QStringList>
+#include <QDir>
+
+#include <KDebug>
+#include <KConfig>
+#include <KConfigGroup>
+
+namespace {
+ bool isParentPresent( const QHash<QString, int> & hash, QDir dir )
+ {
+ bool cd = dir.cdUp();
+ if ( !cd )
+ return false;
+
+ if( hash.contains( dir.absolutePath() ) )
+ return true;
+
+ return isParentPresent( hash, dir );
+ }
+
+ bool isParentPresent( const QHash<QString, int> & hash, QString path )
+ {
+ return isParentPresent( hash, QDir(path) );
+ }
+}
+
+
+Nepomuk::ConfigFolderWatcher::ConfigFolderWatcher( QObject * parent )
+ : QObject( parent )
+{
+ m_serviceConfig = StrigiServiceConfig::self();
+ m_dirWatch = new KInotify( this );
+
+ createWatches();
+ createFoldersHash();
+
+ connect( m_dirWatch, SIGNAL( moved( const QString&, const QString& ) ),
+ this, SLOT( slotMoved( const QString&, const QString& ) ) );
+
+ connect( m_serviceConfig, SIGNAL(configChanged()),
+ this, SLOT(slotConfigChanged()) );
+}
+
+
+Nepomuk::ConfigFolderWatcher::~ConfigFolderWatcher()
+{
+ delete m_dirWatch;
+}
+
+void Nepomuk::ConfigFolderWatcher::slotMoved( const QString& oldName, const QString& newName )
+{
+ if( !m_foldersHash.contains( oldName ) )
+ return;
+
+ kDebug() << "----------------------------------------------";
+ kDebug() << "##############################################";
+ kDebug() << "called with " << oldName << " " << newName;
+
+ //TODO: Optimize
+ QStringList includeFolders = m_serviceConfig->includeFolders();
+ includeFolders.replaceInStrings( oldName, newName );
+
+ QStringList excludeFolders = m_serviceConfig->excludeFolders();
+ excludeFolders.replaceInStrings( oldName, newName );
+
+ //Adjust configuration
+ this->disconnect( m_serviceConfig );
+
+ KConfig strigiConfig( "nepomukstrigirc" );
+ strigiConfig.group( "General" ).writePathEntry( "folders", includeFolders );
+ strigiConfig.group( "General" ).writePathEntry( "exclude folders", excludeFolders );
+
+ connect( m_serviceConfig, SIGNAL(configChanged()),
+ this, SLOT(slotConfigChanged()) );
+
+ //adjust watches
+ m_watches[ oldName ]--;
+ if( m_watches[ oldName ] == 0 ) {
+ kDebug() << "Removing watch : " << oldName;
+ m_dirWatch->removeWatch( oldName );
+ }
+
+ addWatch( newName );
+}
+
+
+void Nepomuk::ConfigFolderWatcher::slotConfigChanged()
+{
+ m_watches.clear();
+ createWatches();
+
+ m_foldersHash.clear();
+ createFoldersHash();
+}
+
+
+void Nepomuk::ConfigFolderWatcher::addWatches(const QStringList & list)
+{
+ foreach( QString path, list ) {
+ addWatch( path );
+ }
+}
+
+void Nepomuk::ConfigFolderWatcher::addWatch( const QString & path )
+{
+ if( isParentPresent( m_watches, path ) ) {
+ m_watches[ path ]++;
+ return;
+ }
+
+ QDir parentPath(path);
+ parentPath.cdUp();
+ const QString p = parentPath.absolutePath();
+
+ kDebug() << "Adding Watch : " << p;
+ m_dirWatch->addWatch( p,
+ KInotify::WatchEvents( KInotify::EventMove|KInotify::EventMoveSelf ),
+ KInotify::WatchFlags() );
+
+ m_watches[ p ] = 1;
+}
+
+
+void Nepomuk::ConfigFolderWatcher::createWatches()
+{
+ QStringList included = m_serviceConfig->includeFolders();
+ addWatches(included);
+
+ QStringList excluded = m_serviceConfig->excludeFolders();
+ addWatches(excluded);
+}
+
+void Nepomuk::ConfigFolderWatcher::createFoldersHash()
+{
+ QStringList included = m_serviceConfig->includeFolders();
+ foreach( QString path, included ) {
+ m_foldersHash.insert( path, true );
+ }
+
+ QStringList excluded = m_serviceConfig->excludeFolders();
+ foreach( QString path, excluded ) {
+ m_foldersHash.insert( path, false );
+ }
+}
\ No newline at end of file
Index: strigiservice.cpp
===================================================================
--- strigiservice.cpp (revision 1117887)
+++ strigiservice.cpp (working copy)
@@ -26,6 +26,7 @@
#include "statuswidget.h"
#include "useractivitymonitor.h"
#include "filewatchserviceinterface.h"
+#include "configfolderwatcher.h"
#include <KDebug>
#include <KDirNotify>
@@ -92,6 +93,8 @@
// start the actual indexing
m_indexScheduler->start();
+
+ new ConfigFolderWatcher(this);
}
else {
kDebug() << "Failed to load sopranobackend Strigi index manager.";
Index: configfolderwatcher.h
===================================================================
--- configfolderwatcher.h (revision 0)
+++ configfolderwatcher.h (revision 0)
@@ -0,0 +1,40 @@
+#ifndef _NEPOMUK_CONFIG_FOLDER_WATCHER_H_
+#define _NEPOMUK_CONFIG_FOLDER_WATCHER_H_
+
+#include <QObject>
+#include <QHash>
+
+class KInotify;
+
+class QStringList;
+
+namespace Nepomuk {
+
+ class StrigiServiceConfig;
+
+ class ConfigFolderWatcher : public QObject {
+ Q_OBJECT
+ public :
+ ConfigFolderWatcher( QObject * parent = 0 );
+ ~ConfigFolderWatcher();
+
+ private Q_SLOTS:
+ void slotMoved( const QString& oldName, const QString& newName );
+ void slotConfigChanged();
+
+ private :
+ KInotify * m_dirWatch;
+ StrigiServiceConfig * m_serviceConfig;
+
+ QHash<QString, int> m_watches;
+ QHash<QString, bool> m_foldersHash;
+
+ void addWatches(const QStringList & list);
+ void addWatch( const QString & path );
+ void createWatches();
+ void createFoldersHash();
+ };
+
+}
+#endif
+
Index: CMakeLists.txt
===================================================================
--- CMakeLists.txt (revision 1117887)
+++ CMakeLists.txt (working copy)
@@ -34,6 +34,8 @@
systray.cpp
statuswidget.cpp
useractivitymonitor.cpp
+ configfolderwatcher.cpp
+ kinotify.cpp
)
soprano_add_ontology(strigiservice_SRCS
_______________________________________________
Nepomuk mailing list
[email protected]
https://mail.kde.org/mailman/listinfo/nepomuk