Hi Vishesh,

I went a little overboard:

I also moved store() and load() calls back into ResourceData. This is
rather trivial. But then you mentioned how ugly it was that ResourceData
could delete itself and how one would have to take care of which methods
to call.
So I changed determineUri() so that it returns the actual ResourceData
to use instead of deleting itself. That way Resource *could* simply do:

m_data = m_data->determineUri()

and it would be enough. And we would not even need the m_resources list.
But then the same thing would have to be done for each copy of that
resource using the ResourceData in question. Thus, I added the method
Resource::determineFInalResourceData which basically does what
ResourceData::replaceWith did before.

So far so good and already confusing enough. But then there is the
problem of the kickoff lists. With proxies we did not have to care about
the old kickoff ids and uris since the ResourceDatas using proxies were
still there "redirecting" to the proxies. Now we delete these old ones.
Thus, if another Resource would be created with the same kickoff id or
uri the whole process would be restarted. That is why I changed the
kickoff id and uri in ResourceData into lists and simply added the new
ResourceData multiple times to the kickoff lists in ResourceManagerPrivate.

I hope that you are not completely confused now. :P
I am still not totally happy with it since it it still rather complex
although having no proxies is already nice...

Cheers,
Sebastian


On 05/29/2010 04:37 PM, Vishesh Handa wrote:
>  
> I think it should work now. I removed the MutexLocker from the inside of
> determineUri().
> 
> - Vishesh Handa
> 
> On Sat, May 29, 2010 at 7:32 PM, Vishesh Handa <[email protected]
> <mailto:[email protected]>> wrote:
> 
> 
>     On Sat, May 29, 2010 at 7:17 PM, Sebastian Trüg <[email protected]
>     <mailto:[email protected]>> wrote:
> 
>         On 05/29/2010 03:34 PM, Vishesh Handa wrote:
>         > On Sat, May 29, 2010 at 5:46 PM, Sebastian Trüg <[email protected]
>         <mailto:[email protected]>
>         > <mailto:[email protected] <mailto:[email protected]>>> wrote:
>         >
>         >     Hehe, this does not help at all. Think about it: in my
>         example there are
>         >     2 Resource instances involved. Thus: 2 mutexes which are
>         locked
>         >     independent of each other. :)
>         >     The mutex is already there in ResourceData. It simply
>         needs to be locked
>         >     in Resource instead of ResourceData::determineUri.
>         >
>         >
>         > Uhh I'm confused. Why don't you handle the multi-threading?
> 
>         Sure, I can do that. :)
> 
> 
>     Wait! Please don't. Let me try. I understand it now. (I think)
>      
> 
> 
>         > I should really learn about multi-threading. If you have a
>         couple of
>         > spare minutes could you explain why my method won't work?
>         >
>         > My rationale -
>         >
>         > Thread 1 :
>         > Resource r1("foo");
>         > r1.property( nao:numericRating )
>         > -> the mutex is locked
>         > -> performs whatever and determines the uri
>         >
>         > Thread 2 :
>         > Resource r2("foo");
>         > r2.setProperty( whatever )
>         > -> the mutex can't get locked so it waits till it does
>         > -> mutex now locked. Thread 1 should have determined the uri
>         by now
>         > -> perform operation
> 
>         Simple: r1 and r2 have different mutex intances. Thus, locking
>         one does
>         not prevent the other from being locked. The idea is that both
>         threads
>         need to lock the same mutex. And that is only possible if the
>         mutex is
>         stored in ResourceData.
> 
> 
>     Oh. Of course. Thanks for explanation. :-)
> 
>     - Vishesh Handa
> 
>         Cheers,
>         Sebastian
> 
> 
> 
Index: resource.h
===================================================================
--- resource.h  (revision 1131454)
+++ resource.h  (working copy)
@@ -737,6 +737,14 @@
         void increaseUsageCount();
 
     private:
+        /**
+         * Determines the final ResourceData and updates m_data if
+         * necessary. This will call ResourceData::determineUri()
+         * and optionally merge with already loaded ResourceData
+         * instances representing the same resource.
+         */
+        void determineFinalResourceData() const;
+
         ResourceData* m_data;
 
         class Private;
Index: resource.cpp
===================================================================
--- resource.cpp        (revision 1131454)
+++ resource.cpp        (working copy)
@@ -47,14 +47,16 @@
 Nepomuk::Resource::Resource()
 {
     m_data = ResourceManager::instance()->d->data( QUrl(), QUrl() );
-    m_data->ref();
+    if ( m_data )
+        m_data->ref( this );
 }
 
 
 Nepomuk::Resource::Resource( ResourceManager* manager )
 {
     m_data = manager->d->data( QUrl(), QUrl() );
-    m_data->ref();
+    if ( m_data )
+        m_data->ref( this );
 }
 
 
@@ -62,7 +64,7 @@
 {
     m_data = res.m_data;
     if ( m_data )
-        m_data->ref();
+        m_data->ref( this );
 }
 
 
@@ -70,7 +72,7 @@
 {
     m_data = ResourceManager::instance()->d->data( uri, type );
     if ( m_data )
-        m_data->ref();
+        m_data->ref( this );
 }
 
 
@@ -78,7 +80,7 @@
 {
     m_data = manager->d->data( uri, type );
     if ( m_data )
-        m_data->ref();
+        m_data->ref( this );
 }
 
 
@@ -86,7 +88,7 @@
 {
     m_data = ResourceManager::instance()->d->data( uri, type );
     if ( m_data )
-        m_data->ref();
+        m_data->ref( this );
 }
 
 
@@ -94,7 +96,7 @@
 {
     m_data = ResourceManager::instance()->d->data( uri, type );
     if ( m_data )
-        m_data->ref();
+        m_data->ref( this );
 }
 
 
@@ -102,7 +104,7 @@
 {
     m_data = manager->d->data( uri, type );
     if ( m_data )
-        m_data->ref();
+        m_data->ref( this );
 }
 
 
@@ -110,26 +112,16 @@
 {
     m_data = data;
     if ( m_data )
-        data->ref();
+        m_data->ref( this );
 }
 
 
 Nepomuk::Resource::~Resource()
 {
     if ( m_data ) {
-        if ( !m_data->deref() ) {
-            //
-            // We delete data objects in one of three cases:
-            // 1. They are not valid and as such not in one of the 
ResourceManagerPrivate kickoff lists
-            // 2. They have a proxy which is the actual thing to reuse later on
-            // 3. The cache is already full and we need to clean up
-            //
-            if ( !m_data->isValid() ||
-                 m_data->proxy() ||
-                 m_data->rm()->dataCacheFull() ) {
-                delete m_data;
-            }
-        }
+        m_data->deref( this );
+        if ( m_data->rm()->shouldBeDeleted( m_data ) )
+            delete m_data;
     }
 }
 
@@ -137,12 +129,12 @@
 Nepomuk::Resource& Nepomuk::Resource::operator=( const Resource& res )
 {
     if( m_data != res.m_data ) {
-        if ( m_data && !m_data->deref() && !m_data->isValid() ) {
+        if ( m_data && !m_data->deref( this ) && 
m_data->rm()->shouldBeDeleted( m_data ) ) {
             delete m_data;
         }
         m_data = res.m_data;
         if ( m_data )
-            m_data->ref();
+            m_data->ref( this );
     }
 
     return *this;
@@ -170,7 +162,7 @@
 QUrl Nepomuk::Resource::resourceUri() const
 {
     if ( m_data ) {
-        m_data->determineUri();
+        determineFinalResourceData();
         return m_data->uri();
     }
     else {
@@ -187,46 +179,37 @@
 
 QUrl Nepomuk::Resource::resourceType() const
 {
-    if ( m_data ) {
-        return m_data->type();
-    }
-    else {
-        return QUrl();
-    }
+    determineFinalResourceData();
+    return m_data->type();
 }
 
 
 QList<QUrl> Nepomuk::Resource::types() const
 {
-    if ( m_data ) {
-        return m_data->allTypes();
-    }
-    else {
-        return QList<QUrl>();
-    }
+    determineFinalResourceData();
+    return m_data->allTypes();
 }
 
 
 void Nepomuk::Resource::setTypes( const QList<QUrl>& types )
 {
-    if ( m_data )
-        m_data->setTypes( types );
+    determineFinalResourceData();
+    m_data->setTypes( types );
 }
 
 
 void Nepomuk::Resource::addType( const QUrl& type )
 {
-    if ( m_data ) {
-        QList<QUrl> tl = types();
-        if( !tl.contains( type ) )
-            setTypes( tl << type );
-    }
+    QList<QUrl> tl = types();
+    if( !tl.contains( type ) )
+        setTypes( tl << type );
 }
 
 
 bool Nepomuk::Resource::hasType( const QUrl& typeUri ) const
 {
-    return m_data ? m_data->hasType( typeUri ) : false;
+    determineFinalResourceData();
+    return m_data->hasType( typeUri );
 }
 
 
@@ -238,12 +221,8 @@
 
 QHash<QUrl, Nepomuk::Variant> Nepomuk::Resource::properties() const
 {
-    if ( m_data ) {
-        return m_data->allProperties();
-    }
-    else {
-        return QHash<QUrl, Nepomuk::Variant>();
-    }
+    determineFinalResourceData();
+    return m_data->allProperties();
 }
 
 
@@ -262,13 +241,15 @@
 
 bool Nepomuk::Resource::hasProperty( const QUrl& uri ) const
 {
-    return m_data ? m_data->hasProperty( uri ) : false;
+    determineFinalResourceData();
+    return m_data->hasProperty( uri );
 }
 
 
 bool Nepomuk::Resource::hasProperty( const Types::Property& p, const Variant& 
v ) const
 {
-    return m_data ? m_data->hasProperty( p.uri(), v ) : false;
+    determineFinalResourceData();
+    return m_data->hasProperty( p.uri(), v );
 }
 
 
@@ -286,12 +267,8 @@
 
 Nepomuk::Variant Nepomuk::Resource::property( const QUrl& uri ) const
 {
-    if ( m_data ) {
-        return m_data->property( uri );
-    }
-    else {
-        return Variant();
-    }
+    determineFinalResourceData();
+    return m_data->property( uri );
 }
 
 
@@ -311,9 +288,8 @@
 
 void Nepomuk::Resource::setProperty( const QUrl& uri, const Nepomuk::Variant& 
value )
 {
-    if ( m_data ) {
-        m_data->setProperty( uri, value );
-    }
+    determineFinalResourceData();
+    m_data->setProperty( uri, value );
 }
 
 
@@ -325,7 +301,7 @@
 
 void Nepomuk::Resource::removeProperty( const QUrl& uri )
 {
-    if ( m_data ) {
+    if ( m_data && m_data->determineUri() ) {
         m_data->removeProperty( uri );
     }
 }
@@ -333,19 +309,17 @@
 
 void Nepomuk::Resource::removeProperty( const QUrl& uri, const Variant& value )
 {
-    if ( m_data ) {
-        QList<Variant> vl = property( uri ).toVariantList();
-        foreach( const Variant& v, value.toVariantList() ) {
-            vl.removeAll( v );
-        }
-        setProperty( uri, Variant( vl ) );
+    QList<Variant> vl = property( uri ).toVariantList();
+    foreach( const Variant& v, value.toVariantList() ) {
+        vl.removeAll( v );
     }
+    setProperty( uri, Variant( vl ) );
 }
 
 
 void Nepomuk::Resource::remove()
 {
-    if ( m_data ) {
+    if ( m_data && m_data->determineUri() ) {
         m_data->remove();
     }
 }
@@ -353,7 +327,12 @@
 
 bool Nepomuk::Resource::exists() const
 {
-    return m_data ? m_data->exists() : false;
+    if ( m_data && m_data->determineUri() ) {
+        return m_data->exists();
+    }
+    else {
+        return false;
+    }
 }
 
 
@@ -478,12 +457,8 @@
 
 Nepomuk::Thing Nepomuk::Resource::pimoThing()
 {
-    if( m_data ) {
-        return m_data->pimoThing();
-    }
-    else {
-        return Thing();
-    }
+    determineFinalResourceData();
+    return m_data->pimoThing();
 }
 
 
@@ -501,8 +476,8 @@
 
     // get the resource URIs since two different ResourceData instances
     // can still represent the same Resource
-    m_data->determineUri();
-    other.m_data->determineUri();
+    determineFinalResourceData();
+    other.determineFinalResourceData();
 
     if( m_data->uri().isEmpty() )
         return *m_data == *other.m_data;
@@ -890,6 +865,46 @@
 }
 
 
+void Nepomuk::Resource::determineFinalResourceData() const
+{
+    m_data->m_determineUriMutex.lock();
+
+    // Get an initialized ResourceData instance
+    ResourceData* oldData = m_data;
+    ResourceData* newData = m_data->determineUri();
+
+    Q_ASSERT(oldData);
+    Q_ASSERT(newData);
+
+    // in case we get an already existing one we update all instances
+    // using the old ResourceData to avoid the overhead of calling
+    // determineUri over and over
+    // Be aware though that in theory another thread could at this point
+    // create another Resource instance pointing to the old ResourceData.
+    if( newData != oldData ) {
+        Q_FOREACH( Resource* res, m_data->m_resources) {
+            res->m_data = newData;
+            oldData->deref( res );
+            newData->ref( res );
+        }
+
+        // actually m_data needs to be replaced by newData in the kickoff 
lists for it to be perfect!
+        // otherwise we loose the advantage we had with proxies where newData 
would still be found by hash lookup
+        // via the oldData kickoff data
+        newData->rm()->addToKickOffList( newData, oldData->m_kickoffUris, 
oldData->m_kickoffIds );
+    }
+
+    // we need to unlock before assigning ourselves to make sure we do not
+    // delete m_data before unlocking
+    oldData->m_determineUriMutex.unlock();
+
+    // FIXME: In theory another thread could at this point create another 
Resource based on oldData.
+
+    if ( !oldData->cnt() )
+        delete oldData;
+}
+
+
 uint Nepomuk::qHash( const Resource& res )
 {
     return qHash(res.resourceUri());
Index: resourcedata.h
===================================================================
--- resourcedata.h      (revision 1131454)
+++ resourcedata.h      (working copy)
@@ -37,6 +37,7 @@
 
 namespace Nepomuk {
 
+    class Resource;
     class ResourceManagerPrivate;
 
     class ResourceData
@@ -45,11 +46,16 @@
         explicit ResourceData( const QUrl& uri, const QString& kickoffId_, 
const QUrl& type_, ResourceManagerPrivate* rm );
         ~ResourceData();
 
-        inline bool ref() {
+        inline bool ref(Nepomuk::Resource* res) {
+            QMutexLocker lock(&m_resourcesMutex);
+            m_resources.push_back( res );
             return m_ref.ref();
         }
 
-        inline bool deref() {
+
+        inline bool deref(Nepomuk::Resource* res) {
+            QMutexLocker lock(&m_resourcesMutex);
+            m_resources.removeAll( res );
             return m_ref.deref();
         }
 
@@ -138,9 +144,17 @@
         /**
          * Searches for the resource in the Nepomuk store using m_kickoffId 
and m_kickoffUri.
          *
-         * \returns true if the resource was found and m_uri is set, false 
otherwise.
+         * This will either get the actual resource URI from the database
+         * and add m_data into ResourceManagerPrivate::m_initializedData
+         * or it will find another ResourceData instance in m_initializedData
+         * which represents the same resource. The ResourceData that should be
+         * used is returned.
+         *
+         * \returns The initialized ResourceData object representing the 
actual resource.
+         *
+         * m_determineUriMutex needs to be locked before calling this method
          */
-        bool determineUri();
+        ResourceData* determineUri();
 
         void invalidateCache();
 
@@ -155,24 +169,32 @@
 
         ResourceManagerPrivate* rm() const { return m_rm; }
 
-        ResourceData* proxy() const { return m_proxyData; }
+        bool shouldBeDeleted() const;
 
-    private:
-        void loadType( const QUrl& type );
+        /// Contains a list of resources which use this ResourceData
+        QList<Resource*> m_resources;
 
-        /// Will reset this instance to 0 as if constructed without parameters
-        /// Used by remove() and deleteData()
-        void resetAll( bool isDelete = false );
-
         /// identifier that was used to construct the resource. Will be used 
by determineUri
         /// to check for nao:identifiers or even nie:urls.
-        QString m_kickoffId;
+        /// This is a list since Resource::determineFinalResourceData may add 
additional ids
+        QStringList m_kickoffIds;
 
         /// the URI that was used to construct the resource. Will be used by 
determineUri
         /// to find the actual resource URI which is either m_kickoffUri 
itself or
         /// a resource URI which relates to m_kickoffUri by nie:url
-        KUrl m_kickoffUri;
+        /// This is a list since Resource::determineFinalResourceData may add 
additional uris
+        KUrl::List m_kickoffUris;
 
+        /// Needs to be locked before calling determineUri()
+        QMutex m_determineUriMutex;
+
+    private:
+        void loadType( const QUrl& type );
+
+        /// Will reset this instance to 0 as if constructed without parameters
+        /// Used by remove() and deleteData()
+        void resetAll( bool isDelete = false );
+
         /// final resource URI created by determineUri
         KUrl m_uri;
 
@@ -184,16 +206,15 @@
 
         QAtomicInt m_ref;
 
-        QMutex m_determineUriMutex;
         mutable QMutex m_modificationMutex;
 
+        QMutex m_resourcesMutex;
+
         /**
-         * Used to virtually merge two data objects representing the same
-         * resource. This happens if the resource was once created using its
-         * actual URI and once via its ID. To prevent early loading we allow
-         * this scenario.
+         * Makes the m_data pointer of all the Resources in m_resources point 
to
+         * rd, instead of 'this'. Handles refernce counting as well.
          */
-        ResourceData* m_proxyData;
+        void replaceWith( ResourceData* rd );
 
         QHash<QUrl, Variant> m_cache;
         bool m_cacheDirty;
Index: resourcedata.cpp
===================================================================
--- resourcedata.cpp    (revision 1131454)
+++ resourcedata.cpp    (working copy)
@@ -56,11 +56,8 @@
 
 
 Nepomuk::ResourceData::ResourceData( const QUrl& uri, const QString& uriOrId, 
const QUrl& type, ResourceManagerPrivate* rm )
-    : m_kickoffId( uriOrId ),
-      m_kickoffUri( uri ),
-      m_mainType( type ),
+    : m_mainType( type ),
       m_modificationMutex(QMutex::Recursive),
-      m_proxyData(0),
       m_cacheDirty(true),
       m_pimoThing(0),
       m_groundingOccurence(0),
@@ -77,10 +74,13 @@
 
     m_rm->dataCnt.ref();
 
-    if( uri.isValid() )
-        m_rm->m_uriKickoffData.insert( uri, this );
-    else if( !uriOrId.isEmpty() )
-        m_rm->m_idKickoffData.insert( uriOrId, this );
+    if( !uri.isEmpty() ) {
+        m_kickoffUris.append( uri );
+    }
+    else if( !uriOrId.isEmpty() ) {
+        m_kickoffIds.append( uriOrId );
+    }
+    m_rm->addToKickOffList( this, m_kickoffUris, m_kickoffIds );
 }
 
 
@@ -94,7 +94,8 @@
 bool Nepomuk::ResourceData::isFile()
 {
     return( m_uri.scheme() == QLatin1String("file") ||
-            m_kickoffUri.scheme() == QLatin1String("file") ||
+            m_nieUrl.scheme() == QLatin1String("file") ||
+            (!m_kickoffUris.isEmpty() && m_kickoffUris.first().scheme() == 
QLatin1String("file")) ||
             constHasType( Soprano::Vocabulary::Xesam::File() ) ||
             constHasType( Nepomuk::Vocabulary::NFO::FileDataObject() ) );
 }
@@ -102,16 +103,12 @@
 
 QUrl Nepomuk::ResourceData::uri() const
 {
-    if( m_proxyData )
-        return m_proxyData->uri();
     return m_uri;
 }
 
 
 QUrl Nepomuk::ResourceData::type()
 {
-    if( m_proxyData )
-        return m_proxyData->type();
     load();
     return m_mainType;
 }
@@ -119,8 +116,6 @@
 
 QList<QUrl> Nepomuk::ResourceData::allTypes()
 {
-    if( m_proxyData )
-        return m_proxyData->allTypes();
     load();
     return m_types;
 }
@@ -128,57 +123,44 @@
 
 void Nepomuk::ResourceData::setTypes( const QList<QUrl>& types )
 {
-    if( m_proxyData ) {
-        m_proxyData->setTypes( types );
-    }
-    else if ( store() ) {
-        QMutexLocker lock(&m_modificationMutex);
+    store();
 
-        // reset types
-        m_types.clear();
-        m_mainType = Soprano::Vocabulary::RDFS::Resource();
+    QMutexLocker lock(&m_modificationMutex);
 
-        QList<Node> nodes;
-        // load types (and set maintype)
-        foreach( const QUrl& url, types ) {
-            loadType( url );
-            nodes << Node( url );
-        }
+    // reset types
+    m_types.clear();
+    m_mainType = Soprano::Vocabulary::RDFS::Resource();
 
-        // update the data store
-        MAINMODEL->updateProperty( m_uri, Soprano::Vocabulary::RDF::type(), 
nodes );
+    QList<Node> nodes;
+    // load types (and set maintype)
+    foreach( const QUrl& url, types ) {
+        loadType( url );
+        nodes << Node( url );
     }
+
+    // update the data store
+    MAINMODEL->updateProperty( m_uri, Soprano::Vocabulary::RDF::type(), nodes 
);
 }
 
 
 
 void Nepomuk::ResourceData::resetAll( bool isDelete )
 {
-    // reset proxy
-    bool hadProxy = false;
-    if( m_proxyData ) {
-        hadProxy = true;
-        if( !m_proxyData->deref() &&
-            rm()->dataCacheFull() )
-            delete m_proxyData;
-        m_proxyData = 0;
-    }
-
     // remove us from all caches (store() will re-insert us later if necessary)
     m_rm->mutex.lock();
-    if( !m_uri.isEmpty() && !hadProxy ) // if we had a proxy we were not in 
m_initializedData ourselves
+    if( !m_uri.isEmpty() )
         m_rm->m_initializedData.remove( m_uri );
-    if( !m_kickoffUri.isEmpty() )
-        m_rm->m_uriKickoffData.remove( m_kickoffUri );
-    if( !m_kickoffId.isEmpty() )
-        m_rm->m_idKickoffData.remove( m_kickoffId );
+    Q_FOREACH( const KUrl& uri, m_kickoffUris )
+        m_rm->m_uriKickoffData.remove( uri );
+    Q_FOREACH( const QString& id, m_kickoffIds )
+        m_rm->m_idKickoffData.remove( id );
     m_rm->mutex.unlock();
 
     // reset all variables
     m_uri = QUrl();
     m_nieUrl = KUrl();
-    m_kickoffId.truncate(0);
-    m_kickoffUri = QUrl();
+    m_kickoffIds.clear();
+    m_kickoffUris.clear();
     m_cache.clear();
     m_cacheDirty = false;
     m_types.clear();
@@ -197,23 +179,14 @@
 
 QHash<QUrl, Nepomuk::Variant> Nepomuk::ResourceData::allProperties()
 {
-    if( m_proxyData )
-        return m_proxyData->allProperties();
-
     load();
-
     return m_cache;
 }
 
 
 bool Nepomuk::ResourceData::hasProperty( const QUrl& uri )
 {
-    if( m_proxyData )
-        return m_proxyData->hasProperty( uri );
-
-    if( !load() )
-        return false;
-
+    load();
     QHash<QUrl, Variant>::const_iterator it = m_cache.constFind( uri );
     if( it == m_cache.constEnd() )
         return false;
@@ -224,12 +197,6 @@
 
 bool Nepomuk::ResourceData::hasProperty( const QUrl& p, const Variant& v )
 {
-    if( m_proxyData )
-        return m_proxyData->hasProperty( p, v );
-
-    if( !load() )
-        return false;
-
     QHash<QUrl, Variant>::const_iterator it = m_cache.constFind( p );
     if( it == m_cache.constEnd() )
         return false;
@@ -246,9 +213,6 @@
 
 bool Nepomuk::ResourceData::hasType( const QUrl& uri )
 {
-    if( m_proxyData )
-        return m_proxyData->hasType( uri );
-
     load();
     return constHasType( uri );
 }
@@ -274,39 +238,19 @@
 
 Nepomuk::Variant Nepomuk::ResourceData::property( const QUrl& uri )
 {
-    if( m_proxyData )
-        return m_proxyData->property( uri );
+    load();
 
-    if ( load() ) {
-        // we need to protect the reading, too. load my be triggered from 
another thread's
-        // connection to a Soprano statement signal
-        QMutexLocker lock(&m_modificationMutex);
+    // we need to protect the reading, too. load my be triggered from another 
thread's
+    // connection to a Soprano statement signal
+    QMutexLocker lock(&m_modificationMutex);
 
-        QHash<QUrl, Variant>::const_iterator it = m_cache.constFind( uri );
-        if ( it == m_cache.constEnd() ) {
-            return Variant();
-        }
-        else {
-            return *it;
-        }
+    QHash<QUrl, Variant>::const_iterator it = m_cache.constFind( uri );
+    if ( it == m_cache.constEnd() ) {
+        return Variant();
     }
     else {
-        return Variant();
+        return *it;
     }
-
-//     Variant v;
-
-//     if ( determineUri() ) {
-//         Soprano::Model* model = m_rm->m_manager->mainModel();
-//         Soprano::StatementIterator it = model->listStatements( 
Soprano::Statement( m_uri, QUrl(uri), Soprano::Node() ) );
-
-//         while ( it.next() ) {
-//             Statement statement = *it;
-//             v.append( Variant::fromNode( statement.object() ) );
-//         }
-//         it.close();
-//     }
-//     return v;
 }
 
 
@@ -314,7 +258,7 @@
 {
     QMutexLocker lock(&m_modificationMutex);
 
-    if ( !determineUri() ) {
+    if ( m_uri.isEmpty() ) {
         QMutexLocker rmlock(&m_rm->mutex);
         // create a random URI and add us to the initialized data, i.e. make 
us "valid"
         m_uri = m_rm->m_manager->generateUniqueUri( QString() );
@@ -322,9 +266,9 @@
 
         // each initialized resource has to be in a kickoff list
         // thus, we make sure that is the case.
-        if( m_kickoffUri.isEmpty() && m_kickoffId.isEmpty() ) {
-            m_kickoffUri = m_uri;
-            m_rm->m_uriKickoffData.insert( m_uri, this );
+        if( m_kickoffUris.isEmpty() && m_kickoffIds.isEmpty() ) {
+            m_kickoffUris.append( m_uri );
+            m_rm->addToKickOffList( this, m_kickoffUris, QStringList() );
         }
     }
 
@@ -335,8 +279,8 @@
         statements.append( Statement( m_uri, 
Soprano::Vocabulary::NAO::created(), Soprano::LiteralValue( 
QDateTime::currentDateTime() ) ) );
 
         // save the kickoff identifier (other identifiers are stored via 
setProperty)
-        if ( !m_kickoffId.isEmpty() ) {
-            statements.append( Statement( m_uri, 
Soprano::Vocabulary::NAO::identifier(), LiteralValue(m_kickoffId) ) );
+        Q_FOREACH ( const QString& id, m_kickoffIds ) {
+            statements.append( Statement( m_uri, 
Soprano::Vocabulary::NAO::identifier(), LiteralValue(id) ) );
         }
 
         // the only situation in which determineUri keeps the kickoff URI is 
for file URLs.
@@ -422,7 +366,7 @@
     if ( m_cacheDirty ) {
         m_cache.clear();
 
-        if ( determineUri() ) {
+        if ( m_uri.isValid() ) {
             Soprano::QueryResultIterator it = 
MAINMODEL->executeQuery(QString("select distinct ?p ?o where { "
                                                                               
"%1 ?p ?o . "
                                                                               
"}").arg(Soprano::Node::resourceToN3(m_uri)),
@@ -477,11 +421,8 @@
 {
     Q_ASSERT( uri.isValid() );
 
-    if( m_proxyData )
-        return m_proxyData->setProperty( uri, value );
-
-    // step 0: make sure this resource is in the store
-    if ( store() ) {
+    if( store() ) {
+        // step 0: make sure this resource is in the store
         QMutexLocker lock(&m_modificationMutex);
 
         QList<Node> valueNodes;
@@ -531,21 +472,19 @@
 void Nepomuk::ResourceData::removeProperty( const QUrl& uri )
 {
     Q_ASSERT( uri.isValid() );
+    Q_ASSERT( m_uri.isValid() );
 
-    if( m_proxyData )
-        return m_proxyData->removeProperty( uri );
-
     QMutexLocker lock(&m_modificationMutex);
 
-    if ( determineUri() ) {
-        m_cache.remove( uri );
-        MAINMODEL->removeProperty( m_uri, uri );
-    }
+    m_cache.remove( uri );
+    MAINMODEL->removeProperty( m_uri, uri );
 }
 
 
 void Nepomuk::ResourceData::remove( bool recursive )
 {
+    Q_ASSERT( m_uri.isValid() );
+
     // trueg: there is one problem we somehow need to work around:
     // if we have a resource with URI X and indentifier Y and we
     // create two ResourceData objects, one from X and one from Y
@@ -558,19 +497,11 @@
     // That way the proxy handling will take care of the rest.
     m_rm->determineAllUris();
 
-    if( m_proxyData ) {
-        m_proxyData->remove( recursive );
-    }
-    else {
-        QMutexLocker lock(&m_modificationMutex);
+    QMutexLocker lock(&m_modificationMutex);
 
-
-        if ( determineUri() ) {
-            MAINMODEL->removeAllStatements( Statement( m_uri, Node(), Node() ) 
);
-            if ( recursive ) {
-                MAINMODEL->removeAllStatements( Statement( Node(), Node(), 
m_uri ) );
-            }
-        }
+    MAINMODEL->removeAllStatements( Statement( m_uri, Node(), Node() ) );
+    if ( recursive ) {
+        MAINMODEL->removeAllStatements( Statement( Node(), Node(), m_uri ) );
     }
 
     resetAll();
@@ -579,179 +510,166 @@
 
 bool Nepomuk::ResourceData::exists()
 {
-    if( m_proxyData )
-        return m_proxyData->exists();
-
-    if( determineUri() ) {
+    if( m_uri.isValid() ) {
         return MAINMODEL->containsAnyStatement( Statement( m_uri, Node(), 
Node() ) );
     }
-    else
+    else {
         return false;
+    }
 }
 
 
 bool Nepomuk::ResourceData::isValid() const
 {
-    if( m_proxyData )
-        return m_proxyData->isValid();
-
-    return( !m_mainType.isEmpty() && ( !m_uri.isEmpty() || 
!m_kickoffUri.isEmpty() || !m_kickoffId.isEmpty() ) );
+    return( !m_mainType.isEmpty() && ( !m_uri.isEmpty() || 
!m_kickoffUris.isEmpty() || !m_kickoffIds.isEmpty() ) );
 }
 
 
-bool Nepomuk::ResourceData::determineUri()
+Nepomuk::ResourceData* Nepomuk::ResourceData::determineUri()
 {
-    if( m_proxyData )
-        return m_proxyData->determineUri();
+    //
+    // Preconditions:
+    // 1. m_kickoffId is not a local file path or URL (use m_kickoffUri for 
that)
+    //
+    // Now for the hard part
+    // We have the following possible situations:
+    // 1. m_uri is already valid
+    //    -> simple, nothing to do
+    //
+    // 2. m_uri is not valid
+    //    -> we need to determine the URI
+    //
+    // 2.1. m_kickoffId is valid
+    // 2.1.1. m_kickoffId is a resource URI
+    //        -> use it as m_uri
+    // 2.1.2. m_kickoffId is a nao:identifier for r
+    //        -> use r as m_uri
+    // 2.1.3. m_kickoffId is not found
+    //        -> create new random m_uri and save m_kickoffId as nao:identifier
+    //
+    // 2.2. m_kickoffUri is valid
+    // 2.2.1. it is a file URL
+    // 2.2.1.1. it is nie:url for r
+    //          -> use r as m_uri
+    // 2.2.1.2. it points to a file on a removable device for which we have a 
filex:/ URL
+    //          -> use the r in r nie:url filex:/...
+    // 2.2.1.3. it is a file which is not an object in some nie:url relation
+    //          -> create new random m_uri and use kickoffUriOrId() as m_nieUrl
+    //
+    if( m_uri.isEmpty() ) {
 
-    else {
-        //
-        // Preconditions:
-        // 1. m_kickoffId is not a local file path or URL (use m_kickoffUri 
for that)
-        //
-        // Now for the hard part
-        // We have the following possible situations:
-        // 1. m_uri is already valid
-        //    -> simple, nothing to do
-        //
-        // 2. m_uri is not valid
-        //    -> we need to determine the URI
-        //
-        // 2.1. m_kickoffId is valid
-        // 2.1.1. m_kickoffId is a resource URI
-        //        -> use it as m_uri
-        // 2.1.2. m_kickoffId is a nao:identifier for r
-        //        -> use r as m_uri
-        // 2.1.3. m_kickoffId is not found
-        //        -> create new random m_uri and save m_kickoffId as 
nao:identifier
-        //
-        // 2.2. m_kickoffUri is valid
-        // 2.2.1. it is a file URL
-        // 2.2.1.1. it is nie:url for r
-        //          -> use r as m_uri
-        // 2.2.1.2. it points to a file on a removable device for which we 
have a filex:/ URL
-        //          -> use the r in r nie:url filex:/...
-        // 2.2.1.3. it is a file which is not an object in some nie:url 
relation
-        //          -> create new random m_uri and use kickoffUriOrId() as 
m_nieUrl
-        //
-        QMutexLocker lock(&m_determineUriMutex);
+        Soprano::Model* model = MAINMODEL;
 
-        if( m_uri.isEmpty() ) {
-
-            Soprano::Model* model = MAINMODEL;
-
-            if( !m_kickoffId.isEmpty() ) {
-                //
-                // The kickoffUriOrId is actually a URI
-                //
-                KUrl uriFromKickoffId(m_kickoffId);
-                if( model->containsAnyStatement( uriFromKickoffId, Node(), 
Node() )) {
-                    m_uri = uriFromKickoffId;
-                }
-
-                //
-                // Check if the kickoffUriOrId is a resource identifier or a 
resource URI
-                //
-                else {
-                    QString query = QString::fromLatin1("select distinct ?r ?o 
where { { ?r %1 %2 . } UNION { %3 ?p ?o . } . } LIMIT 1")
-                                    .arg( 
Soprano::Node::resourceToN3(Soprano::Vocabulary::NAO::identifier()) )
-                                    .arg( 
Soprano::Node::literalToN3(m_kickoffId) )
-                                    .arg( 
Soprano::Node::resourceToN3(KUrl(m_kickoffId)) );
-                    Soprano::QueryResultIterator it = model->executeQuery( 
query, Soprano::Query::QueryLanguageSparql );
-                    if( it.next() ) {
-                        m_uri = it["r"].uri();
-                        if( m_uri.isEmpty() ) {
-                            m_uri = KUrl(m_kickoffId);
-                        }
-                        it.close();
-                    }
-                }
+        if( !m_kickoffIds.isEmpty() ) {
+            //
+            // The kickoffUriOrId is actually a URI
+            //
+            KUrl uriFromKickoffId(m_kickoffIds.first());
+            if( model->containsAnyStatement( uriFromKickoffId, Node(), Node() 
)) {
+                m_uri = uriFromKickoffId;
             }
 
-            else if( !m_kickoffUri.isEmpty() ) {
-                //
-                // In one query determine if the URI is already used as 
resource URI or as
-                // nie:url
-                //
-                QString query = QString::fromLatin1("select distinct ?r ?o 
where { "
-                                                    "{ ?r %1 %2 . 
FILTER(?r!=%2) . } "
-                                                    "UNION "
-                                                    "{ %2 ?p ?o . } "
-                                                    "} LIMIT 1")
-                                .arg( 
Soprano::Node::resourceToN3(Nepomuk::Vocabulary::NIE::url()) )
-                                .arg( 
Soprano::Node::resourceToN3(m_kickoffUri) );
+            //
+            // Check if the kickoffUriOrId is a resource identifier or a 
resource URI
+            //
+            else {
+                QString query = QString::fromLatin1("select distinct ?r ?o 
where { { ?r %1 %2 . } UNION { %3 ?p ?o . } . } LIMIT 1")
+                                .arg( 
Soprano::Node::resourceToN3(Soprano::Vocabulary::NAO::identifier()) )
+                                .arg( 
Soprano::Node::literalToN3(m_kickoffIds.first()) )
+                                .arg( 
Soprano::Node::resourceToN3(KUrl(m_kickoffIds.first())) );
                 Soprano::QueryResultIterator it = model->executeQuery( query, 
Soprano::Query::QueryLanguageSparql );
                 if( it.next() ) {
-                    QUrl uri = it["r"].uri();
-                    if( uri.isEmpty() ) {
-                        m_uri = m_kickoffUri;
+                    m_uri = it["r"].uri();
+                    if( m_uri.isEmpty() ) {
+                        m_uri = KUrl(m_kickoffIds.first());
                     }
-                    else {
-                        m_uri = uri;
-                        m_nieUrl = m_kickoffUri;
-                    }
                     it.close();
                 }
-                else if( m_kickoffUri.scheme() == QLatin1String("file") ) {
-                    //
-                    // This is the hard part: The file may still be saved 
using a filex:/ URL
-                    // We have to determine if that is the case. For that we 
need to look if the URL
-                    // starts with any of the mounted filesystems' mount paths 
and then reconstruct
-                    // the filex:/ URL. Since that is quite some work which 
involved Solid and, thus,
-                    // DBus calls we simply call the removable storage service 
directly.
-                    //
-                    // If there is no resource yet we create a new uri in 
store()
-                    //
+            }
+        }
 
-                    //
-                    // We create a new dbus connection to protect us from 
multi-thread related crashes.
-                    //
-                    KUrl resourceUri = QDBusReply<QString>( 
QDBusInterface(QLatin1String("org.kde.nepomuk.services.nepomukremovablestorageservice"),
-                                                                           
QLatin1String("/nepomukremovablestorageservice"),
-                                                                           
QLatin1String("org.kde.nepomuk.RemovableStorage"),
-                                                                           
DBusConnectionPool::threadConnection())
-                                                            .call( 
QLatin1String("resourceUriFromLocalFileUrl"),
-                                                                   
m_kickoffUri.url() ) ).value();
-                    if( !resourceUri.isEmpty() ) {
-                        m_uri = resourceUri;
-                    }
-
-                    m_nieUrl = m_kickoffUri;
+        else if( !m_kickoffUris.isEmpty() ) {
+            //
+            // In one query determine if the URI is already used as resource 
URI or as
+            // nie:url
+            //
+            QString query = QString::fromLatin1("select distinct ?r ?o where { 
"
+                                                "{ ?r %1 %2 . FILTER(?r!=%2) . 
} "
+                                                "UNION "
+                                                "{ %2 ?p ?o . } "
+                                                "} LIMIT 1")
+                            .arg( 
Soprano::Node::resourceToN3(Nepomuk::Vocabulary::NIE::url()) )
+                            .arg( 
Soprano::Node::resourceToN3(m_kickoffUris.first()) );
+            Soprano::QueryResultIterator it = model->executeQuery( query, 
Soprano::Query::QueryLanguageSparql );
+            if( it.next() ) {
+                QUrl uri = it["r"].uri();
+                if( uri.isEmpty() ) {
+                    m_uri = m_kickoffUris.first();
                 }
-                else if( m_kickoffUri.scheme() == QLatin1String("nepomuk") ) {
-                    // for nepomuk URIs we simply use the kickoff URI as 
resource URI
-                    m_uri = m_kickoffUri;
-                }
                 else {
-                    // for everything else we use m_kickoffUri as nie:url with 
a new random m_uri
-                    m_nieUrl = m_kickoffUri;
+                    m_uri = uri;
+                    m_nieUrl = m_kickoffUris.first();
                 }
+                it.close();
             }
+            else if( m_kickoffUris.first().scheme() == QLatin1String("file") ) 
{
+                //
+                // This is the hard part: The file may still be saved using a 
filex:/ URL
+                // We have to determine if that is the case. For that we need 
to look if the URL
+                // starts with any of the mounted filesystems' mount paths and 
then reconstruct
+                // the filex:/ URL. Since that is quite some work which 
involved Solid and, thus,
+                // DBus calls we simply call the removable storage service 
directly.
+                //
+                // If there is no resource yet we create a new uri in store()
+                //
 
+                //
+                // We create a new dbus connection to protect us from 
multi-thread related crashes.
+                //
+                KUrl resourceUri = QDBusReply<QString>( 
QDBusInterface(QLatin1String("org.kde.nepomuk.services.nepomukremovablestorageservice"),
+                                                                       
QLatin1String("/nepomukremovablestorageservice"),
+                                                                       
QLatin1String("org.kde.nepomuk.RemovableStorage"),
+                                                                       
DBusConnectionPool::threadConnection())
+                                                        .call( 
QLatin1String("resourceUriFromLocalFileUrl"),
+                                                               
m_kickoffUris.first().url() ) ).value();
+                if( !resourceUri.isEmpty() ) {
+                    m_uri = resourceUri;
+                }
+
+                m_nieUrl = m_kickoffUris.first();
+            }
+            else if( m_kickoffUris.first().scheme() == 
QLatin1String("nepomuk") ) {
+                // for nepomuk URIs we simply use the kickoff URI as resource 
URI
+                m_uri = m_kickoffUris.first();
+            }
             else {
-                // no kickoff values. We will only create a new random URI in 
store()
-                return false;
+                // for everything else we use m_kickoffUri as nie:url with a 
new random m_uri
+                m_nieUrl = m_kickoffUris.first();
             }
+        }
 
-            //
-            // Move us to the final data hash now that the URI is known
-            //
-            if( !m_uri.isEmpty() ) {
-                QMutexLocker rmlock(&m_rm->mutex);
+        else {
+            // no kickoff values. We will only create a new random URI in 
store()
+            return this;
+        }
 
-                ResourceDataHash::iterator it = 
m_rm->m_initializedData.find(m_uri);
-                if( it == m_rm->m_initializedData.end() ) {
-                    m_rm->m_initializedData.insert( m_uri, this );
-                }
-                else {
-                    m_proxyData = it.value();
-                    m_proxyData->ref();
-                }
+        //
+        // Move us to the final data hash now that the URI is known
+        //
+        if( !m_uri.isEmpty() ) {
+            QMutexLocker rmlock(&m_rm->mutex);
+
+            ResourceDataHash::iterator it = 
m_rm->m_initializedData.find(m_uri);
+            if( it == m_rm->m_initializedData.end() ) {
+                m_rm->m_initializedData.insert( m_uri, this );
             }
+            else {
+                return it.value();
+            }
         }
-
-        return !m_uri.isEmpty();
     }
+
+    return this;
 }
 
 
@@ -796,30 +714,25 @@
 
 bool Nepomuk::ResourceData::operator==( const ResourceData& other ) const
 {
-    const ResourceData* that = this;
-    if( m_proxyData )
-        that = m_proxyData;
-
-    if( that == &other )
+    if( this == &other )
         return true;
 
-    return( that->m_uri == other.m_uri &&
-            that->m_mainType == other.m_mainType &&
-            that->m_kickoffUri == other.m_kickoffUri &&
-            that->m_kickoffId == other.m_kickoffId );
+    return( m_uri == other.m_uri &&
+            m_mainType == other.m_mainType &&
+            m_kickoffUris == other.m_kickoffUris &&
+            m_kickoffIds == other.m_kickoffIds );
 }
 
 
 QDebug Nepomuk::ResourceData::operator<<( QDebug dbg ) const
 {
-    dbg << QString::fromLatin1("[kickoffid: %1, kickoffuri: %2, uri: %3, type: 
%4, ref: %5")
-        .arg(m_kickoffId,
-             m_kickoffUri.url(),
+    dbg << QString::fromLatin1("[kickoffid: %1; kickoffuri: %2; uri: %3; type: 
%4; ref: %5")
+        .arg(m_kickoffIds.join(QLatin1String(",")),
+             m_kickoffUris.toStringList().join(QLatin1String(",")),
              m_uri.url(),
              m_mainType.toString())
         .arg(m_ref);
-    if(m_proxyData)
-        dbg << QLatin1String(", proxy: " ) << *m_proxyData;
+
     return dbg << QLatin1String("]");
 }
 
Index: resourcemanager_p.h
===================================================================
--- resourcemanager_p.h (revision 1131454)
+++ resourcemanager_p.h (working copy)
@@ -97,7 +97,7 @@
          */
         ResourceData* data( const QUrl& uri, const QUrl& type );
 
-        bool dataCacheFull();
+        bool dataCacheFull() const;
 
         /**
          * Delete unused ResourceData objects from the cache.
@@ -115,6 +115,10 @@
          */
         void determineAllUris();
 
+        bool shouldBeDeleted( ResourceData* rd ) const;
+
+        void addToKickOffList( ResourceData* rd, const KUrl::List& uris, const 
QStringList& ids );
+
         QList<ResourceData*> allResourceData();
         QList<ResourceData*> allResourceDataOfType( const QUrl& type );
         QList<ResourceData*> allResourceDataWithProperty( const QUrl& _uri, 
const Variant& v );
Index: resourcemanager.h
===================================================================
--- resourcemanager.h   (revision 1131454)
+++ resourcemanager.h   (working copy)
@@ -40,8 +40,12 @@
     /**
      * \class ResourceManager resourcemanager.h Nepomuk/ResourceManager
      *
-     * \brief The ResourceManager is the central \a %KMetaData configuration 
point.
+     * \brief The ResourceManager is the central \a %Nepomuk configuration 
point.
      *
+     * Use the initialized() method to check the availabity of the %Nepomuk 
system.
+     * Signals nepomukSystemStarted() and nepomukSystemStopped() can be used to
+     * enable or disable Nepomuk-specific GUI elements.
+     *
      * \author Sebastian Trueg <[email protected]>
      */
     class NEPOMUK_EXPORT ResourceManager : public QObject
@@ -64,14 +68,14 @@
 
         /**
          * Initialize the Nepomuk framework. This method will initialize the 
communication with
-         * the local Nepomuk-KDE services, ie. the data repository.
+         * the local Nepomuk-KDE services, ie. the data repository. It will 
trigger a reconnect
+         * to the %Nepomuk database.
          *
-         * When using multiple threads make sure to call this method in the 
main thread
+         * There is normally no reason to call this method manually except 
when using multiple
+         * threads. In that case it is highly recommended to call this method 
in the main thread
          * before doing anything else.
          *
          * \return 0 if all necessary components could be found and -1 
otherwise.
-         *
-         * FIXME: introduce error codes and human readable translated error 
messages.
          */
         int init();
 
Index: resourcemanager.cpp
===================================================================
--- resourcemanager.cpp (revision 1131454)
+++ resourcemanager.cpp (working copy)
@@ -197,7 +197,7 @@
 }
 
 
-bool Nepomuk::ResourceManagerPrivate::dataCacheFull()
+bool Nepomuk::ResourceManagerPrivate::dataCacheFull() const
 {
     return dataCnt >= 1000;
 }
@@ -230,6 +230,26 @@
 }
 
 
+bool Nepomuk::ResourceManagerPrivate::shouldBeDeleted( ResourceData * rd ) 
const
+{
+    //
+    // We delete data objects in one of two cases:
+    // 1. They are not valid and as such not in one of the 
ResourceManagerPrivate kickoff lists
+    // 2. The cache is already full and we need to clean up
+    //
+    return( !rd->cnt() && ( !rd->isValid() || dataCacheFull() ));
+}
+
+
+void Nepomuk::ResourceManagerPrivate::addToKickOffList( ResourceData* rd, 
const KUrl::List& uris, const QStringList& ids )
+{
+    Q_FOREACH( const KUrl& uri, uris )
+        m_uriKickoffData.insert( uri, rd );
+    Q_FOREACH( const QString& id, ids )
+        m_idKickoffData.insert( id, rd );
+}
+
+
 void Nepomuk::ResourceManagerPrivate::_k_storageServiceInitialized( bool 
success )
 {
     if( success ) {
_______________________________________________
Nepomuk mailing list
[email protected]
https://mail.kde.org/mailman/listinfo/nepomuk

Reply via email to