~ubuntu-branches/ubuntu/quantal/kde-runtime/quantal

« back to all changes in this revision

Viewing changes to nepomuk/services/filewatch/metadatamover.cpp

  • Committer: Package Import Robot
  • Author(s): Philip Muškovac
  • Date: 2012-06-03 21:50:00 UTC
  • mto: This revision was merged to the branch mainline in revision 21.
  • Revision ID: package-import@ubuntu.com-20120603215000-vn7oarsq0ynrydj5
Tags: upstream-4.8.80
Import upstream version 4.8.80

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* This file is part of the KDE Project
2
 
   Copyright (c) 2009-2011 Sebastian Trueg <trueg@kde.org>
3
 
 
4
 
   This library is free software; you can redistribute it and/or
5
 
   modify it under the terms of the GNU Library General Public
6
 
   License version 2 as published by the Free Software Foundation.
7
 
 
8
 
   This library is distributed in the hope that it will be useful,
9
 
   but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11
 
   Library General Public License for more details.
12
 
 
13
 
   You should have received a copy of the GNU Library General Public License
14
 
   along with this library; see the file COPYING.LIB.  If not, write to
15
 
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16
 
   Boston, MA 02110-1301, USA.
17
 
*/
18
 
 
19
 
#include "metadatamover.h"
20
 
#include "nepomukfilewatch.h"
21
 
#include "datamanagement.h"
22
 
 
23
 
#include <QtCore/QTimer>
24
 
 
25
 
#include <Soprano/Model>
26
 
#include <Soprano/Node>
27
 
#include <Soprano/NodeIterator>
28
 
#include <Soprano/QueryResultIterator>
29
 
#include <Soprano/LiteralValue>
30
 
 
31
 
#include <Nepomuk/Vocabulary/NIE>
32
 
 
33
 
#include <KDebug>
34
 
 
35
 
 
36
 
Nepomuk::MetadataMover::MetadataMover( Soprano::Model* model, QObject* parent )
37
 
    : QObject( parent ),
38
 
      m_queueMutex(QMutex::Recursive),
39
 
      m_model( model )
40
 
{
41
 
    // setup the main update queue timer
42
 
    m_queueTimer = new QTimer(this);
43
 
    connect(m_queueTimer, SIGNAL(timeout()),
44
 
            this, SLOT(slotWorkUpdateQueue()),
45
 
            Qt::DirectConnection);
46
 
 
47
 
    // setup the cleanup timer which removes requests that are done
48
 
    m_recentlyFinishedRequestsTimer = new QTimer(this);
49
 
    connect( m_recentlyFinishedRequestsTimer, SIGNAL( timeout() ),
50
 
             this, SLOT( slotClearRecentlyFinishedRequests() ),
51
 
             Qt::DirectConnection );
52
 
    m_recentlyFinishedRequestsTimer->setInterval( 30000 );
53
 
}
54
 
 
55
 
 
56
 
Nepomuk::MetadataMover::~MetadataMover()
57
 
{
58
 
}
59
 
 
60
 
 
61
 
void Nepomuk::MetadataMover::moveFileMetadata( const KUrl& from, const KUrl& to )
62
 
{
63
 
//    kDebug() << from << to;
64
 
    Q_ASSERT( !from.path().isEmpty() && from.path() != "/" );
65
 
    Q_ASSERT( !to.path().isEmpty() && to.path() != "/" );
66
 
 
67
 
    QMutexLocker lock(&m_queueMutex);
68
 
 
69
 
    UpdateRequest req( from, to );
70
 
    if ( !m_updateQueue.contains( req ) &&
71
 
         !m_recentlyFinishedRequests.contains( req ) )
72
 
        m_updateQueue.enqueue( req );
73
 
 
74
 
    QTimer::singleShot(0, this, SLOT(slotStartUpdateTimer()));
75
 
}
76
 
 
77
 
 
78
 
void Nepomuk::MetadataMover::removeFileMetadata( const KUrl& file )
79
 
{
80
 
    Q_ASSERT( !file.path().isEmpty() && file.path() != "/" );
81
 
    removeFileMetadata( KUrl::List() << file );
82
 
}
83
 
 
84
 
 
85
 
void Nepomuk::MetadataMover::removeFileMetadata( const KUrl::List& files )
86
 
{
87
 
    kDebug() << files;
88
 
    QMutexLocker lock(&m_queueMutex);
89
 
 
90
 
    foreach( const KUrl& file, files ) {
91
 
        UpdateRequest req( file );
92
 
        if ( !m_updateQueue.contains( req ) &&
93
 
             !m_recentlyFinishedRequests.contains( req ) )
94
 
            m_updateQueue.enqueue( req );
95
 
    }
96
 
 
97
 
    QTimer::singleShot(0, this, SLOT(slotStartUpdateTimer()));
98
 
}
99
 
 
100
 
 
101
 
void Nepomuk::MetadataMover::slotWorkUpdateQueue()
102
 
{
103
 
    // lock for initial iteration
104
 
    QMutexLocker lock(&m_queueMutex);
105
 
 
106
 
    // work the queue
107
 
    if( !m_updateQueue.isEmpty() ) {
108
 
        UpdateRequest updateRequest = m_updateQueue.dequeue();
109
 
        m_recentlyFinishedRequests.insert( updateRequest );
110
 
 
111
 
        // unlock after queue utilization
112
 
        lock.unlock();
113
 
 
114
 
//        kDebug() << "========================= handling" << updateRequest.source() << updateRequest.target();
115
 
 
116
 
        // an empty second url means deletion
117
 
        if( updateRequest.target().isEmpty() ) {
118
 
            removeMetadata( updateRequest.source() );
119
 
        }
120
 
        else {
121
 
            const KUrl from = updateRequest.source();
122
 
            const KUrl to = updateRequest.target();
123
 
 
124
 
            // We do NOT get deleted messages for overwritten files! Thus, we
125
 
            // have to remove all metadata for overwritten files first.
126
 
            removeMetadata( to );
127
 
 
128
 
            // and finally update the old statements
129
 
            updateMetadata( from, to );
130
 
        }
131
 
 
132
 
//        kDebug() << "========================= done with" << updateRequest.source() << updateRequest.target();
133
 
    }
134
 
    else {
135
 
        kDebug() << "All update requests handled. Stopping timer.";
136
 
        m_queueTimer->stop();
137
 
    }
138
 
}
139
 
 
140
 
 
141
 
void Nepomuk::MetadataMover::removeMetadata( const KUrl& url )
142
 
{
143
 
//    kDebug() << url;
144
 
 
145
 
    if ( url.isEmpty() ) {
146
 
        kDebug() << "empty path. Looks like a bug somewhere...";
147
 
    }
148
 
    else {
149
 
        const bool isFolder = url.url().endsWith('/');
150
 
        Nepomuk::removeResources(QList<QUrl>() << url);
151
 
 
152
 
        if( isFolder ) {
153
 
            //
154
 
            // Recursively remove children
155
 
            // We cannot use the nie:isPartOf relation since only children could have metadata. Thus, we do a regex
156
 
            // match on all files and folders below the URL we got.
157
 
            //
158
 
            // CAUTION: The trailing slash on the from URL is essential! Otherwise we might match the newly added
159
 
            //          URLs, too (in case a rename only added chars to the name)
160
 
            //
161
 
            const QString query = QString::fromLatin1( "select distinct ?r where { "
162
 
                                                    "?r %1 ?url . "
163
 
                                                    "FILTER(REGEX(STR(?url),'^%2')) . "
164
 
                                                    "}" )
165
 
                                .arg( Soprano::Node::resourceToN3( Nepomuk::Vocabulary::NIE::url() ),
166
 
                                        url.url(KUrl::AddTrailingSlash) );
167
 
 
168
 
            //
169
 
            // We cannot use one big loop since our updateMetadata calls below can change the iterator
170
 
            // which could have bad effects like row skipping. Thus, we handle the urls in chunks of
171
 
            // cached items.
172
 
            //
173
 
            while ( 1 ) {
174
 
                QList<QUrl> urls;
175
 
                Soprano::QueryResultIterator it = m_model->executeQuery( query + QLatin1String( " LIMIT 20" ),
176
 
                                                                         Soprano::Query::QueryLanguageSparql );
177
 
                while(it.next()) {
178
 
                    urls << it[0].uri();
179
 
                }
180
 
                if ( !urls.isEmpty() ) {
181
 
                    Nepomuk::removeResources(urls);
182
 
                }
183
 
                else {
184
 
                    break;
185
 
                }
186
 
            }
187
 
        }
188
 
    }
189
 
}
190
 
 
191
 
 
192
 
void Nepomuk::MetadataMover::updateMetadata( const KUrl& from, const KUrl& to )
193
 
{
194
 
    kDebug() << from << "->" << to;
195
 
 
196
 
    if ( m_model->executeQuery(QString::fromLatin1("ask where { { %1 ?p ?o . } UNION { ?r nie:url %1 . } . }")
197
 
                               .arg(Soprano::Node::resourceToN3(from)),
198
 
                               Soprano::Query::QueryLanguageSparql).boolValue() ) {
199
 
        Nepomuk::setProperty(QList<QUrl>() << from, Nepomuk::Vocabulary::NIE::url(), QVariantList() << to);
200
 
    }
201
 
    else {
202
 
        //
203
 
        // If we have no metadata yet we need to tell the file indexer (if running) so it can
204
 
        // create the metadata in case the target folder is configured to be indexed.
205
 
        //
206
 
        emit movedWithoutData( to.path() );
207
 
    }
208
 
}
209
 
 
210
 
 
211
 
// removes all finished requests older than 1 minute
212
 
void Nepomuk::MetadataMover::slotClearRecentlyFinishedRequests()
213
 
{
214
 
    QMutexLocker lock( &m_queueMutex );
215
 
    QSet<UpdateRequest>::iterator it = m_recentlyFinishedRequests.begin();
216
 
    while ( it != m_recentlyFinishedRequests.end() ) {
217
 
        const UpdateRequest& req = *it;
218
 
        if ( req.timestamp().secsTo( QDateTime::currentDateTime() ) > 60 ) {
219
 
            it = m_recentlyFinishedRequests.erase( it );
220
 
        }
221
 
        else {
222
 
            ++it;
223
 
        }
224
 
    }
225
 
 
226
 
    if(m_recentlyFinishedRequests.isEmpty()) {
227
 
        kDebug() << "No more old requests. Stopping timer.";
228
 
        m_recentlyFinishedRequestsTimer->stop();
229
 
    }
230
 
}
231
 
 
232
 
 
233
 
// start the timer in the update thread
234
 
void Nepomuk::MetadataMover::slotStartUpdateTimer()
235
 
{
236
 
    if(!m_queueTimer->isActive()) {
237
 
        m_queueTimer->start();
238
 
    }
239
 
    if(!m_recentlyFinishedRequestsTimer->isActive()) {
240
 
        m_recentlyFinishedRequestsTimer->start();
241
 
    }
242
 
}
243
 
 
244
 
#include "metadatamover.moc"