Hi Vishesh,

please find attached an updated version of the patch. There is still at
least one problem: run the resourcetest and see it crashing. This is due
to determineUri deleting "this". determineUri() is called all over the
place. I think the one solution is to move that call into Resource as I
already did with store().
The other thing is the comment in ResourceData::remove(). We need to
make sure that is still working.

Cheers,
Sebastian

On 05/18/2010 01:46 PM, Vishesh Handa wrote:
> 
> 
> On Tue, May 18, 2010 at 4:07 PM, Sebastian Trüg <[email protected]
> <mailto:[email protected]>> wrote:
> 
>     On 05/18/2010 12:30 PM, Vishesh Handa wrote:
>     >     2. Don't we need to protect m_resources via a QMutex?
>     >
>     >
>     > I'm currently blissfully unaware about concurrent programming. I
>     assure
>     > you I'm trying to learn, but till then could you take care of it?
> 
>     ok, will do.
> 
>     >     [3. Wouldn't shoudBeDeleted() make more sense in
>     >     ResourceManagerPrivate?]
>     >
>     > :-/ It checks if a ResourceData should be deleted. I considered making
>     > it static but this approach had less clutter. Could you please explain
>     > why it should be in ResourceManagerPrivate?
> 
>     I thought that conceptually it is the resourcemanager maintaining the
>     resourcedata objects. So it should also be the one to decide when one
>     has to be deleted.
> 
> 
> Okay. I've changed it.
> 
> The shouldBeDeleted function is currently called twice. Two times in
> Resource (destructor and operator==), and once in ResourceData::replaceWith.
> 
> - Vishesh Handa
> 
> 
>     >     As for ResourceManagerPrivate: this is just how it is done in
>     KDE: it is
>     >     a convention to name private classes that way. You can look in
>     KDE and
>     >     Qt code all over the place and find these private classes.
>     Their main
>     >     purpose is to keep as much member variables and methods out of
>     the main
>     >     class as possible to make it possible to add and remove those
>     without
>     >     breaking binary compatibility.
>     >
>     >
>     > Yea. I know. The "pimpl" idiom. :)
>     >
>     >     I will apply the patch and test it.
>     >
>     > Okay. I'll do the same.
>     >
>     > - Vishesh Handa
>     >
>     >
>     >     Cheers,
>     >     Sebastian
>     >
>     >     On 05/16/2010 04:11 PM, Vishesh Handa wrote:
>     >     > Cleaned up the code a little bit.
>     >     > - fixed a small bug in Resource::~Resource(). (my fault)
>     >     > - m_resources is now managed along with reference counting.
>     >     > - Added a function ResourceData::shouldBeDeleted() to avoid
>     >     duplication
>     >     > of code.
>     >     >
>     >     > I think the shouldBeDeleted() function should be in another
>     patch.
>     >     >
>     >     > Btw, this code still hasn't been extensively tested. I'll do the
>     >     testing
>     >     > later on. I just though I should share the patch so that I
>     can get
>     >     your
>     >     > comments.
>     >     >
>     >     > - Vishesh Handa
>     >
>     >
> 
> 
Index: resourcemanager_p.h
===================================================================
--- resourcemanager_p.h (revision 1128573)
+++ 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,8 @@
          */
         void determineAllUris();
 
+        bool shouldBeDeleted( ResourceData* rd ) const;
+
         QList<ResourceData*> allResourceData();
         QList<ResourceData*> allResourceDataOfType( const QUrl& type );
         QList<ResourceData*> allResourceDataWithProperty( const QUrl& _uri, 
const Variant& v );
Index: resourcedata.cpp
===================================================================
--- resourcedata.cpp    (revision 1128573)
+++ resourcedata.cpp    (working copy)
@@ -60,7 +60,6 @@
       m_kickoffUri( uri ),
       m_mainType( type ),
       m_modificationMutex(QMutex::Recursive),
-      m_proxyData(0),
       m_cacheDirty(true),
       m_pimoThing(0),
       m_groundingOccurence(0),
@@ -102,16 +101,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 +114,6 @@
 
 QList<QUrl> Nepomuk::ResourceData::allTypes()
 {
-    if( m_proxyData )
-        return m_proxyData->allTypes();
     load();
     return m_types;
 }
@@ -128,45 +121,30 @@
 
 void Nepomuk::ResourceData::setTypes( const QList<QUrl>& types )
 {
-    if( m_proxyData ) {
-        m_proxyData->setTypes( types );
-    }
-    else if ( store() ) {
-        QMutexLocker lock(&m_modificationMutex);
+    QMutexLocker lock(&m_modificationMutex);
 
-        // reset types
-        m_types.clear();
-        m_mainType = Soprano::Vocabulary::RDFS::Resource();
+    // reset types
+    m_types.clear();
+    m_mainType = Soprano::Vocabulary::RDFS::Resource();
 
-        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 );
+    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 );
@@ -197,20 +175,13 @@
 
 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;
 
@@ -224,9 +195,6 @@
 
 bool Nepomuk::ResourceData::hasProperty( const QUrl& p, const Variant& v )
 {
-    if( m_proxyData )
-        return m_proxyData->hasProperty( p, v );
-
     if( !load() )
         return false;
 
@@ -246,9 +214,6 @@
 
 bool Nepomuk::ResourceData::hasType( const QUrl& uri )
 {
-    if( m_proxyData )
-        return m_proxyData->hasType( uri );
-
     load();
     return constHasType( uri );
 }
@@ -274,9 +239,6 @@
 
 Nepomuk::Variant Nepomuk::ResourceData::property( const QUrl& uri )
 {
-    if( m_proxyData )
-        return m_proxyData->property( uri );
-
     if ( load() ) {
         // we need to protect the reading, too. load my be triggered from 
another thread's
         // connection to a Soprano statement signal
@@ -359,7 +321,7 @@
     // that m_types contains more than one element: if we loaded them)
     // The first type, however, can be set at creation time to any value
     if ( m_mainType != Soprano::Vocabulary::RDFS::Resource() &&
-        !MAINMODEL->containsAnyStatement( m_uri, 
Soprano::Vocabulary::RDF::type(), m_mainType ) ) {
+         !MAINMODEL->containsAnyStatement( m_uri, 
Soprano::Vocabulary::RDF::type(), m_mainType ) ) {
         statements.append( Statement( m_uri, Soprano::Vocabulary::RDF::type(), 
m_mainType ) );
     }
 
@@ -476,54 +438,48 @@
 {
     Q_ASSERT( uri.isValid() );
 
-    if( m_proxyData )
-        return m_proxyData->setProperty( uri, value );
+    QMutexLocker lock(&m_modificationMutex);
 
-    // step 0: make sure this resource is in the store
-    if ( store() ) {
-        QMutexLocker lock(&m_modificationMutex);
+    QList<Node> valueNodes;
 
-        QList<Node> valueNodes;
-
-        // make sure resource values are in the store
-        if ( value.simpleType() == qMetaTypeId<Resource>() ) {
-            QList<Resource> l = value.toResourceList();
-            for( QList<Resource>::iterator resIt = l.begin(); resIt != 
l.end(); ++resIt ) {
-                resIt->m_data->store();
-            }
+    // make sure resource values are in the store
+    if ( value.simpleType() == qMetaTypeId<Resource>() ) {
+        QList<Resource> l = value.toResourceList();
+        for( QList<Resource>::iterator resIt = l.begin(); resIt != l.end(); 
++resIt ) {
+            resIt->m_data->store();
         }
+    }
 
-        // add the actual property statements
+    // add the actual property statements
 
-        // one-to-one Resource
-        if( value.isResource() ) {
-            valueNodes.append( value.toUrl() );
-        }
+    // one-to-one Resource
+    if( value.isResource() ) {
+        valueNodes.append( value.toUrl() );
+    }
 
-        // one-to-many Resource
-        else if( value.isResourceList() ) {
-            const QList<QUrl>& l = value.toUrlList();
-            for( QList<QUrl>::const_iterator resIt = l.constBegin(); resIt != 
l.constEnd(); ++resIt ) {
-                valueNodes.append( *resIt );
-            }
+    // one-to-many Resource
+    else if( value.isResourceList() ) {
+        const QList<QUrl>& l = value.toUrlList();
+        for( QList<QUrl>::const_iterator resIt = l.constBegin(); resIt != 
l.constEnd(); ++resIt ) {
+            valueNodes.append( *resIt );
         }
+    }
 
-        // one-to-many literals
-        else if( value.isList() ) {
-            valueNodes = Nepomuk::valuesToRDFNodes( value );
-        }
+    // one-to-many literals
+    else if( value.isList() ) {
+        valueNodes = Nepomuk::valuesToRDFNodes( value );
+    }
 
-        // one-to-one literal
-        else {
-            valueNodes.append( Nepomuk::valueToRDFNode( value ) );
-        }
+    // one-to-one literal
+    else {
+        valueNodes.append( Nepomuk::valueToRDFNode( value ) );
+    }
 
-        // update the cache for now
-        m_cache[uri] = value;
+    // update the cache for now
+    m_cache[uri] = value;
 
-        // update the store
-        MAINMODEL->updateProperty( m_uri, uri, valueNodes );
-    }
+    // update the store
+    MAINMODEL->updateProperty( m_uri, uri, valueNodes );
 }
 
 
@@ -531,9 +487,6 @@
 {
     Q_ASSERT( uri.isValid() );
 
-    if( m_proxyData )
-        return m_proxyData->removeProperty( uri );
-
     QMutexLocker lock(&m_modificationMutex);
 
     if ( determineUri() ) {
@@ -557,18 +510,12 @@
     // 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 ) );
-            }
+    if ( determineUri() ) {
+        MAINMODEL->removeAllStatements( Statement( m_uri, Node(), Node() ) );
+        if ( recursive ) {
+            MAINMODEL->removeAllStatements( Statement( Node(), Node(), m_uri ) 
);
         }
     }
 
@@ -578,9 +525,6 @@
 
 bool Nepomuk::ResourceData::exists()
 {
-    if( m_proxyData )
-        return m_proxyData->exists();
-
     if( determineUri() ) {
         return MAINMODEL->containsAnyStatement( Statement( m_uri, Node(), 
Node() ) );
     }
@@ -591,166 +535,170 @@
 
 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() ) );
 }
 
 
 bool 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
+    //
+    QMutexLocker lock(&m_determineUriMutex);
 
-    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);
+    if( m_uri.isEmpty() ) {
 
-        if( m_uri.isEmpty() ) {
+        Soprano::Model* model = MAINMODEL;
 
-            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_kickoffId.isEmpty() ) {
+            //
+            // The kickoffUriOrId is actually a URI
+            //
+            KUrl uriFromKickoffId(m_kickoffId);
+            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 . } "
-                                                    "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_kickoffId) )
+                                .arg( 
Soprano::Node::resourceToN3(KUrl(m_kickoffId)) );
                 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_kickoffId);
                     }
-                    else {
-                        m_uri = uri;
-                        m_nieUrl = uri;
-                    }
                     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_kickoffUri.scheme() == QLatin1String("nepomuk") ) {
-                    // for nepomuk URIs we simply use the kickoff URI as 
resource URI
+        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 . } "
+                                                "UNION "
+                                                "{ %2 ?p ?o . } "
+                                                "} LIMIT 1")
+                            .arg( 
Soprano::Node::resourceToN3(Nepomuk::Vocabulary::NIE::url()) )
+                            .arg( Soprano::Node::resourceToN3(m_kickoffUri) );
+            Soprano::QueryResultIterator it = model->executeQuery( query, 
Soprano::Query::QueryLanguageSparql );
+            if( it.next() ) {
+                QUrl uri = it["r"].uri();
+                if( uri.isEmpty() ) {
                     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 = uri;
                 }
+                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_kickoffUri.scheme() == QLatin1String("nepomuk") ) {
+                // for nepomuk URIs we simply use the kickoff URI as resource 
URI
+                m_uri = m_kickoffUri;
+            }
             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_kickoffUri;
             }
+        }
 
-            //
-            // 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 false;
+        }
 
-                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 {
+                // As the ResourceData already exists in m_initializedData, we 
simply
+                // make all the the Resources which contain "this" 
ResourceData, point
+                // to the initialized ResourceData instead.
+                replaceWith( it.value() );
+            }
         }
+    }
 
-        return !m_uri.isEmpty();
+    return !m_uri.isEmpty();
+}
+
+
+void Nepomuk::ResourceData::replaceWith( Nepomuk::ResourceData* rd )
+{
+    Q_FOREACH( Resource* res, m_resources ) {
+        res->m_data = rd;
+        rd->ref( res );
     }
+    delete this;
 }
 
 
@@ -795,17 +743,13 @@
 
 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_kickoffUri == other.m_kickoffUri &&
+            m_kickoffId == other.m_kickoffId );
 }
 
 
@@ -817,8 +761,7 @@
              m_uri.url(),
              m_mainType.toString())
         .arg(m_ref);
-    if(m_proxyData)
-        dbg << QLatin1String(", proxy: " ) << *m_proxyData;
+
     return dbg << QLatin1String("]");
 }
 
Index: resourcemanager.cpp
===================================================================
--- resourcemanager.cpp (revision 1128573)
+++ resourcemanager.cpp (working copy)
@@ -84,12 +84,9 @@
     }
 
     if( it == end ) {
-        ResourceData* d = new ResourceData( url, QString(), type, this );
-//         kDebug() << "--------------------------- Created new ResourceData:" 
<< *d;
-        return d;
+        return new ResourceData( url, QString(), type, this );
     }
     else {
-//         kDebug() << "---------------------------- Reusing" << *it.value() 
<< "for" << uri;
         return it.value();
     }
 }
@@ -111,8 +108,7 @@
 
     KickoffDataHash::iterator it = m_idKickoffData.find( uriOrId );
     if( it == m_idKickoffData.end() ) {
-        ResourceData* d = new ResourceData( QUrl(), uriOrId, type, this );
-        return d;
+        return new ResourceData( QUrl(), uriOrId, type, this );
     }
     else {
         return it.value();
@@ -197,7 +193,7 @@
 }
 
 
-bool Nepomuk::ResourceManagerPrivate::dataCacheFull()
+bool Nepomuk::ResourceManagerPrivate::dataCacheFull() const
 {
     return dataCnt >= 1000;
 }
@@ -230,6 +226,20 @@
 }
 
 
+bool Nepomuk::ResourceManagerPrivate::shouldBeDeleted( ResourceData* rd ) const
+{
+    if ( rd->cnt() )
+        return false;
+
+    //
+    // 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->isValid() || dataCacheFull() );
+}
+
+
 void Nepomuk::ResourceManagerPrivate::_k_storageServiceInitialized( bool 
success )
 {
     if( success ) {
Index: resourcedata.h
===================================================================
--- resourcedata.h      (revision 1128573)
+++ resourcedata.h      (working copy)
@@ -25,6 +25,7 @@
 #include <QtCore/QList>
 #include <QtCore/QHash>
 #include <QtCore/QMutex>
+#include <QtCore/QMutexLocker>
 #include <QtCore/QAtomicInt>
 
 #include "variant.h"
@@ -37,6 +38,7 @@
 
 namespace Nepomuk {
 
+    class Resource;
     class ResourceManagerPrivate;
 
     class ResourceData
@@ -45,11 +47,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();
         }
 
@@ -113,6 +120,8 @@
          * This is also the only place where a new URI is generated via 
ResourceManager::generateUniqueUri()
          * in case m_uri is empty.
          *
+         * Be aware that store() may replace this ResourceData entirely and 
delete it!
+         *
          * \sa exists, setProperty
          */
         bool store();
@@ -155,7 +164,7 @@
 
         ResourceManagerPrivate* rm() const { return m_rm; }
 
-        ResourceData* proxy() const { return m_proxyData; }
+        bool shouldBeDeleted() const;
 
     private:
         void loadType( const QUrl& type );
@@ -187,13 +196,15 @@
         QMutex m_determineUriMutex;
         mutable QMutex m_modificationMutex;
 
+        /// Contains a list of resources which contain this ResourceData
+        QList<Resource*> m_resources;
+        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: resource.cpp
===================================================================
--- resource.cpp        (revision 1128573)
+++ 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;
@@ -209,8 +201,9 @@
 
 void Nepomuk::Resource::setTypes( const QList<QUrl>& types )
 {
-    if ( m_data )
+    if ( m_data && m_data->store() ) {
         m_data->setTypes( types );
+    }
 }
 
 
@@ -311,7 +304,7 @@
 
 void Nepomuk::Resource::setProperty( const QUrl& uri, const Nepomuk::Variant& 
value )
 {
-    if ( m_data ) {
+    if ( m_data && m_data->store() ) {
         m_data->setProperty( uri, value );
     }
 }
_______________________________________________
Nepomuk mailing list
[email protected]
https://mail.kde.org/mailman/listinfo/nepomuk

Reply via email to