[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-commits
Subject: branches/KDE/4.5/kdebase/runtime/nepomuk/services/filewatch
From: Sebastian Trueg <sebastian () trueg ! de>
Date: 2010-11-23 13:16:36
Message-ID: 20101123131636.CF32FAC8A2 () svn ! kde ! org
[Download RAW message or body]
SVN commit 1199996 by trueg:
Backport of two important fixes:
* Fixed KInotify which sometimes thought / was deleted which resulted in removal of \
all indexed files from the index.
* Do not delete all graphs which contain information about removed files. Instead \
remove the resources since the graphs might also contain information about other \
resources.
BUG: 251446
M +1 -0 CMakeLists.txt
AM invalidfileresourcecleaner.cpp [License: GPL (v2/3)]
AM invalidfileresourcecleaner.h [License: GPL (v2/3)]
M +67 -45 kinotify.cpp
M +2 -2 kinotify.h
M +3 -0 metadatamover.cpp
M +12 -68 nepomukfilewatch.cpp
M +1 -1 nepomukfilewatch.h
--- branches/KDE/4.5/kdebase/runtime/nepomuk/services/filewatch/CMakeLists.txt \
#1199995:1199996 @@ -16,6 +16,7 @@
nepomukfilewatch.cpp
metadatamover.cpp
updaterequest.cpp
+ invalidfileresourcecleaner.cpp
)
qt4_add_dbus_interface(SRCS ../../interfaces/org.kde.nepomuk.Strigi.xml \
strigiserviceinterface)
--- branches/KDE/4.5/kdebase/runtime/nepomuk/services/filewatch/kinotify.cpp \
#1199995:1199996 @@ -44,13 +44,21 @@
// is a variable length array
const int EVENT_BUFFER_SIZE = EVENT_STRUCT_SIZE + 1024*16;
- QByteArray normalizePath( const QByteArray& path ) {
+ QByteArray stripTrailingSlash( const QByteArray& path ) {
QByteArray p( path );
if ( p.endsWith( '/' ) )
p.truncate( p.length()-1 );
return p;
}
+
+ QByteArray concatPath( const QByteArray& p1, const QByteArray& p2 ) {
+ QByteArray p(p1);
+ if( p.isEmpty() || p[p.length()-1] != '/' )
+ p.append('/');
+ p.append(p2);
+ return p;
}
+}
class KInotify::Private
{
@@ -66,8 +74,9 @@
close();
}
- QHash<int, QString> cookies;
- QHash<int, QByteArray> pathHash;
+ QHash<int, QByteArray> cookies;
+ QHash<int, QByteArray> watchPathHash;
+ QHash<QByteArray, int> pathWatchHash;
/// queue of paths to install watches for
QQueue<QByteArray> pathsToWatch;
@@ -97,13 +106,16 @@
}
bool addWatch( const QByteArray& path ) {
+ kDebug() << path;
// we always need the unmount event to maintain our path hash
const int mask = mode|flags|EventUnmount;
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 normalized = stripTrailingSlash( path );
+ watchPathHash.insert( wd, normalized );
+ pathWatchHash.insert( normalized, wd );
return true;
}
else {
@@ -123,7 +135,7 @@
if ( !addWatch( path ) )
return false;
- int len = offsetof(struct dirent, d_name) +
+ const int len = offsetof(struct dirent, d_name) +
pathconf(path.data(), _PC_NAME_MAX) + 1;
struct dirent* entry = ( struct dirent* )new char[len];
@@ -144,7 +156,7 @@
qstrcmp( entry->d_name, "." ) &&
qstrcmp( entry->d_name, ".." ) ) {
bool isDir = true;
- QByteArray subDir = path + '/' + QByteArray::fromRawData( \
entry->d_name, qstrlen( entry->d_name ) ); + QByteArray subDir = \
concatPath( path, QByteArray::fromRawData( entry->d_name, qstrlen( entry->d_name ) ) \
); if ( entry->d_type == DT_UNKNOWN ) {
struct stat buf;
lstat( subDir.data(), &buf );
@@ -169,7 +181,8 @@
}
void removeWatch( int wd ) {
- pathHash.remove( wd );
+ kDebug() << wd << watchPathHash[wd];
+ pathWatchHash.remove( watchPathHash.take( wd ) );
inotify_rm_watch( inotify(), wd );
}
@@ -248,15 +261,9 @@
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;
+ const QByteArray p( stripTrailingSlash( QFile::encodeName( path ) ) );
+ return d->pathWatchHash.contains(p);
}
- return false;
-}
bool KInotify::addWatch( const QString& path, WatchEvents mode, WatchFlags flags )
@@ -271,15 +278,16 @@
}
-// TODO: do this more efficiently
bool KInotify::removeWatch( const QString& path )
{
+ kDebug() << path;
QByteArray encodedPath = QFile::encodeName( path );
- QHash<int, QByteArray>::iterator it = d->pathHash.begin();
- while ( it != d->pathHash.end() ) {
+ QHash<int, QByteArray>::iterator it = d->watchPathHash.begin();
+ while ( it != d->watchPathHash.end() ) {
if ( it.value().startsWith( encodedPath ) ) {
inotify_rm_watch( d->inotify(), it.key() );
- it = d->pathHash.erase( it );
+ d->pathWatchHash.remove(it.value());
+ it = d->watchPathHash.erase( it );
}
else {
++it;
@@ -292,61 +300,64 @@
void KInotify::slotEvent( int socket )
{
// read at least one event
- int len = read( socket, d->eventBuffer, EVENT_BUFFER_SIZE );
+ const int len = read( socket, d->eventBuffer, EVENT_BUFFER_SIZE );
int i = 0;
while ( i < len && len-i >= EVENT_STRUCT_SIZE ) {
- struct inotify_event* event = ( struct inotify_event* )&d->eventBuffer[i];
+ const struct inotify_event* event = ( struct inotify_event* \
)&d->eventBuffer[i];
- QByteArray encodedPath = QByteArray::fromRawData( event->name, event->len );
+ QByteArray path;
- if ( encodedPath[0] != '/' ) {
- encodedPath = d->pathHash.value( event->wd ) + '/' + encodedPath;
+ // the event name only contains an interesting value if we get an event for \
a file/folder inside + // a watched folder. Otherwise we should ignore it
+ if ( event->mask & (EventDeleteSelf|EventMoveSelf) ) {
+ path = d->watchPathHash.value( event->wd );
}
+ else {
+ // we cannot use event->len here since it contains the size of the \
buffer and not the length of the string + const QByteArray eventName = \
QByteArray::fromRawData( event->name, qstrlen(event->name) ); + const \
QByteArray hashedPath = d->watchPathHash.value( event->wd ); + path = \
concatPath( hashedPath, eventName ); + }
- QString path = QFile::decodeName( encodedPath );
-
// now signal the event
if ( event->mask & EventAccess) {
// kDebug() << path << "EventAccess";
- emit accessed( path );
+ emit accessed( QFile::decodeName(path) );
}
if ( event->mask & EventAttributeChange ) {
// kDebug() << path << "EventAttributeChange";
- emit attributeChanged( path );
+ emit attributeChanged( QFile::decodeName(path) );
}
if ( event->mask & EventCloseWrite ) {
// kDebug() << path << "EventCloseWrite";
- emit closedWrite( path );
+ emit closedWrite( QFile::decodeName(path) );
}
if ( event->mask & EventCloseRead ) {
// kDebug() << path << "EventCloseRead";
- emit closedRead( path );
+ emit closedRead( QFile::decodeName(path) );
}
if ( event->mask & EventCreate ) {
// kDebug() << path << "EventCreate";
if ( event->mask & IN_ISDIR ) {
// FIXME: store the mode and flags somewhere
- addWatch( encodedPath, d->mode, d->flags );
+ addWatch( path, d->mode, d->flags );
}
- emit created( path );
+ emit created( QFile::decodeName(path) );
}
if ( event->mask & EventDelete ) {
// kDebug() << path << "EventDelete";
- if ( event->mask & IN_ISDIR ) {
- d->removeWatch( event->wd );
+ // we watch all folders recursively. Thus, folder removing is reported \
in DeleteSelf. + if( !(event->mask & IN_ISDIR) )
+ emit deleted( QFile::decodeName(path), false );
}
- emit deleted( path );
- }
if ( event->mask & EventDeleteSelf ) {
// kDebug() << path << "EventDeleteSelf";
- if ( event->mask & IN_ISDIR ) {
d->removeWatch( event->wd );
+ emit deleted( QFile::decodeName(path), event->mask & IN_ISDIR );
}
- emit deleted( path );
- }
if ( event->mask & EventModify ) {
// kDebug() << path << "EventModify";
- emit modified( path );
+ emit modified( QFile::decodeName(path) );
}
if ( event->mask & EventMoveSelf ) {
// kDebug() << path << "EventMoveSelf";
@@ -358,10 +369,21 @@
if ( event->mask & EventMoveTo ) {
// check if we have a cookie for this one
if ( d->cookies.contains( event->cookie ) ) {
- QString oldPath = d->cookies[event->cookie];
- d->cookies.remove( event->cookie );
+ const QByteArray oldPath = d->cookies.take(event->cookie);
+
+ // update the path cache
+ if( event->mask & IN_ISDIR ) {
+ QHash<QByteArray, int>::iterator it = \
d->pathWatchHash.find(oldPath); + if( it != d->pathWatchHash.end() \
) { + kDebug() << oldPath << path;
+ const int wd = it.value();
+ d->watchPathHash[wd] = path;
+ d->pathWatchHash.erase(it);
+ d->pathWatchHash.insert( path, wd );
+ }
+ }
// kDebug() << oldPath << "EventMoveTo" << path;
- emit moved( oldPath, path );
+ emit moved( QFile::encodeName(oldPath), QFile::decodeName(path) );
}
else {
kDebug() << "No cookie for move information of" << path;
@@ -369,14 +391,14 @@
}
if ( event->mask & EventOpen ) {
// kDebug() << path << "EventOpen";
- emit opened( path );
+ emit opened( QFile::decodeName(path) );
}
if ( event->mask & EventUnmount ) {
// kDebug() << path << "EventUnmount. removing from path hash";
if ( event->mask & IN_ISDIR ) {
d->removeWatch( event->wd );
}
- emit unmounted( path );
+ emit unmounted( QFile::decodeName(path) );
}
if ( event->mask & EventQueueOverflow ) {
// This should not happen since we grab all events as soon as they \
arrive
--- branches/KDE/4.5/kdebase/runtime/nepomuk/services/filewatch/kinotify.h \
#1199995:1199996 @@ -32,7 +32,7 @@
Q_OBJECT
public:
- KInotify( QObject* parent );
+ KInotify( QObject* parent = 0 );
~KInotify();
/**
@@ -127,7 +127,7 @@
* Emitted if a watched file or folder has been deleted.
* This includes files in watched foldes (KInotify::EventDelete and \
KInotify::EventDeleteSelf)
*/
- void deleted( const QString& file );
+ void deleted( const QString& file, bool isFolder );
/**
* Emitted if a watched file is modified (KInotify::EventModify)
--- branches/KDE/4.5/kdebase/runtime/nepomuk/services/filewatch/metadatamover.cpp \
#1199995:1199996 @@ -176,12 +176,14 @@
kDebug() << "empty path. Looks like a bug somewhere...";
}
else {
+ const bool isFolder = url.url().endsWith('/');
Resource res( url );
if ( res.exists() ) {
kDebug() << "removing metadata for file" << url << "with resource URI" \
<< res.resourceUri(); res.remove();
}
+ if( isFolder ) {
//
// Recursively remove children
// We cannot use the nie:isPartOf relation since only children could have \
metadata. Thus, we do a regex @@ -217,6 +219,7 @@
}
}
}
+}
void Nepomuk::MetadataMover::updateMetadata( const KUrl& from, const KUrl& to, bool \
includeChildren )
--- branches/KDE/4.5/kdebase/runtime/nepomuk/services/filewatch/nepomukfilewatch.cpp \
#1199995:1199996 @@ -19,6 +19,7 @@
#include "nepomukfilewatch.h"
#include "metadatamover.h"
#include "strigiserviceinterface.h"
+#include "invalidfileresourcecleaner.h"
#include "nie.h"
#ifdef BUILD_KINOTIFY
@@ -45,69 +46,6 @@
NEPOMUK_EXPORT_SERVICE( Nepomuk::FileWatch, "nepomukfilewatch")
-
-namespace {
-
- class RemoveInvalidThread : public QThread {
- public :
- RemoveInvalidThread(QObject* parent = 0);
- ~RemoveInvalidThread();
- void run();
-
- private:
- bool m_stopped;
- };
-
- RemoveInvalidThread::RemoveInvalidThread(QObject* parent)
- : QThread(parent),
- m_stopped( false )
- {
- connect( this, SIGNAL(finished()), this, SLOT(deleteLater()) );
- }
-
- RemoveInvalidThread::~RemoveInvalidThread()
- {
- // gently terminate the thread
- m_stopped = true;
- wait();
- }
-
- void RemoveInvalidThread::run()
- {
- kDebug() << "Searching for invalid local file entries";
- //
- // Since the removal of the graphs could intefere with the iterator and \
result
- // in jumping of rows (worst case) we cache all graphs to remove
- //
- QList<Soprano::Node> graphsToRemove;
- QString query = QString::fromLatin1( "select distinct ?g ?url where { "
- "?r %1 ?url. "
- "FILTER(regex(str(?url), 'file://')) . \
"
- "graph ?g { ?r ?p ?o. } }" )
- .arg( Soprano::Node::resourceToN3( \
Nepomuk::Vocabulary::NIE::url() ) );
- Soprano::QueryResultIterator it = \
Nepomuk::ResourceManager::instance()->mainModel()->executeQuery( query, \
Soprano::Query::QueryLanguageSparql );
-
- while( it.next() && !m_stopped ) {
- QUrl url( it["url"].uri() );
- QString file = url.toLocalFile();
-
- if( !file.isEmpty() && !QFile::exists(file) ) {
- kDebug() << "REMOVING " << file;
- graphsToRemove << it["g"];
- }
- }
-
- Q_FOREACH( const Soprano::Node& g, graphsToRemove ) {
- if ( m_stopped )
- break;
- Nepomuk::ResourceManager::instance()->mainModel()->removeContext( g );
- }
- kDebug() << "Done searching for invalid local file entries";
- }
-
-}
-
-
Nepomuk::FileWatch::FileWatch( QObject* parent, const QList<QVariant>& )
: Service( parent )
{
@@ -126,8 +64,8 @@
connect( m_dirWatch, SIGNAL( moved( const QString&, const QString& ) ),
this, SLOT( slotFileMoved( const QString&, const QString& ) ) );
- connect( m_dirWatch, SIGNAL( deleted( const QString& ) ),
- this, SLOT( slotFileDeleted( const QString& ) ) );
+ connect( m_dirWatch, SIGNAL( deleted( const QString&, bool ) ),
+ this, SLOT( slotFileDeleted( const QString&, bool ) ) );
connect( m_dirWatch, SIGNAL( created( const QString& ) ),
this, SLOT( slotFileCreated( const QString& ) ) );
connect( m_dirWatch, SIGNAL( modified( const QString& ) ),
@@ -149,7 +87,7 @@
connectToKDirWatch();
#endif
- (new RemoveInvalidThread(this))->start();
+ (new InvalidFileResourceCleaner(this))->start();
}
@@ -192,14 +130,20 @@
kDebug() << urls;
+ if(!urls.isEmpty())
m_metadataMover->removeFileMetadata( urls );
}
-void Nepomuk::FileWatch::slotFileDeleted( const QString& urlString )
+void Nepomuk::FileWatch::slotFileDeleted( const QString& urlString, bool isDir )
{
- slotFilesDeleted( QStringList( urlString ) );
+ // Directories must always end with a trailing slash '/'
+ QString url = urlString;
+ if( isDir && url[ url.length() - 1 ] != '/') {
+ url.append('/');
}
+ slotFilesDeleted( QStringList( url ) );
+}
void Nepomuk::FileWatch::slotFileCreated( const QString& path )
--- branches/KDE/4.5/kdebase/runtime/nepomuk/services/filewatch/nepomukfilewatch.h \
#1199995:1199996 @@ -59,7 +59,7 @@
private Q_SLOTS:
void slotFileMoved( const QString& from, const QString& to );
- void slotFileDeleted( const QString& path );
+ void slotFileDeleted( const QString& path, bool isDir );
void slotFilesDeleted( const QStringList& path );
void slotFileCreated( const QString& );
void slotFileModified( const QString& );
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic