[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    KDE/kdelibs/kded
From:       David Faure <faure () kde ! org>
Date:       2010-11-26 0:04:20
Message-ID: 20101126000420.1E411AC8A2 () svn ! kde ! org
[Download RAW message or body]

SVN commit 1200847 by dfaure:

Fix two bugs that were compensating each other in the unittest here:
1) kbuildsycoca would not emit databaseChanged("...") for resources where desktop \
files had been deleted 2) a name clash ("screensaver.desktop" in both servicetypes \
and services) made kbuildsycoca4 always emit databaseChanged("services")

And of course the unittest was for "deleting a desktop file in the services resource" \
so it was passing by pure chance (and not on Volker's machine which didn't have both \
desktop files).

Fixed 2) by using resource+path as the key in that dict rather than just path.
and fixed 1) by looking at g_ctimeDict at the end, to see which resources are still \
there (which needed the fix for 2 in the first place)

The fix for 1) uncovers a new bug though: databaseChanged("apps") is always emitted, \
so we never go into the fast path of "no need to save to disk"; I'll look at this \
tomorrow.


 M  +37 -22    kbuildsycoca.cpp  
 M  +3 -0      kbuildsycoca.h  
 M  +75 -39    kctimefactory.cpp  
 M  +29 -9     kctimefactory.h  


--- trunk/KDE/kdelibs/kded/kbuildsycoca.cpp #1200846:1200847
@@ -71,13 +71,12 @@
 static KBuildServiceFactory *g_serviceFactory = 0;
 static KBuildServiceGroupFactory *g_buildServiceGroupFactory = 0;
 static KSycocaFactory *g_currentFactory = 0;
-static KCTimeInfo *g_ctimeInfo = 0;
-static QHash<QString, quint32> *g_ctimeDict = 0;
+static KCTimeInfo *g_ctimeInfo = 0; // factory
+static KCTimeDict *g_ctimeDict = 0; // old timestamps
 static QByteArray g_resource = 0;
 static KBSEntryDict *g_currentEntryDict = 0;
 static KBSEntryDict *g_serviceGroupEntryDict = 0;
-static KSycocaEntryListList *g_allEntries = 0;
-static QStringList *g_changeList = 0;
+static KSycocaEntryListList *g_allEntries = 0; // entries from existing ksycoca
 static QStringList *g_allResourceDirs = 0;
 static bool g_changed = false;
 static KSycocaEntry::List g_tempStorage;
@@ -113,7 +112,7 @@
 
 KSycocaEntry::Ptr KBuildSycoca::createEntry(const QString &file, bool addToFactory)
 {
-   quint32 timeStamp = g_ctimeInfo->ctime(file);
+   quint32 timeStamp = g_ctimeInfo->dict()->ctime(file, g_resource);
    if (!timeStamp)
    {
       timeStamp = KGlobal::dirs()->calcResourceHash( g_resource, file,
@@ -123,7 +122,7 @@
    if (g_allEntries)
    {
       assert(g_ctimeDict);
-      quint32 oldTimestamp = g_ctimeDict->value( file, 0 );
+      quint32 oldTimestamp = g_ctimeDict->ctime(file, g_resource);
 
       if (timeStamp && (timeStamp == oldTimestamp))
       {
@@ -137,20 +136,23 @@
          // remove from g_ctimeDict; if g_ctimeDict is not empty
          // after all files have been processed, it means
          // some files were removed since last time
-         g_ctimeDict->remove( file );
+         if (file.contains("fake"))
+            kDebug(7021) << g_resource << "reusing (and removing) old entry \
[\"fake\"] for:" << file; +         g_ctimeDict->remove(file, g_resource);
       }
       else if (oldTimestamp)
       {
          g_changed = true;
-         kDebug(7021) << "modified:" << file;
+         g_ctimeDict->remove(file, g_resource);
+         kDebug(7021) << "modified:" << file << "in" << g_resource.constData();
       }
       else
       {
          g_changed = true;
-         kDebug(7021) << "new:" << file;
+         kDebug(7021) << "new:" << file << "in" << g_resource.constData();
       }
    }
-   g_ctimeInfo->addCTime(file, timeStamp );
+   g_ctimeInfo->dict()->addCTime(file, g_resource, timeStamp);
    if (!entry)
    {
       // Create a new entry
@@ -173,7 +175,7 @@
    return KService::Ptr::staticCast(entry);
 }
 
-// returns false if the database is up to date
+// returns false if the database is up to date, true if it needs to be saved
 bool KBuildSycoca::build()
 {
   typedef QLinkedList<KBSEntryDict *> KBSEntryDictList;
@@ -280,12 +282,24 @@
      if (g_changed || !g_allEntries)
      {
         uptodate = false;
-        g_changeList->append(g_resource);
+        //kDebug() << "CHANGED:" << g_resource;
+        m_changedResources.append(g_resource);
      }
   }
 
   bool result = !uptodate || (g_ctimeDict && !g_ctimeDict->isEmpty());
+  if (g_ctimeDict && !g_ctimeDict->isEmpty()) {
+      //kDebug() << "Still in time dict:";
+      //g_ctimeDict->dump();
+      // ## It seems entries filtered out by vfolder are still in there,
+      // so we end up always saving ksycoca, i.e. this method never returns false
 
+      // Get the list of resources from which some files were deleted
+      const QStringList resources = g_ctimeDict->resourceList();
+      kDebug() << "Still in the time dict (i.e. deleted files)" << resources;
+      m_changedResources += resources;
+  }
+
   if (result || bMenuTest)
   {
      g_resource = "apps";
@@ -309,7 +323,8 @@
      if (g_changed || !g_allEntries)
      {
         uptodate = false;
-        g_changeList->append(g_resource);
+        //kDebug() << "CHANGED:" << g_resource;
+        m_changedResources.append(g_resource);
      }
      if (bMenuTest) {
          result = false;
@@ -331,7 +346,7 @@
      QString directoryFile = subMenu->directoryFile;
      if (directoryFile.isEmpty())
         directoryFile = subName+".directory";
-     quint32 timeStamp = g_ctimeInfo->ctime(directoryFile);
+     quint32 timeStamp = g_ctimeInfo->dict()->ctime(directoryFile, g_resource);
      if (!timeStamp) {
         timeStamp = KGlobal::dirs()->calcResourceHash( g_resource, directoryFile,
                                                        KStandardDirs::Recursive );
@@ -340,7 +355,7 @@
      KServiceGroup::Ptr entry;
      if (g_allEntries)
      {
-        quint32 oldTimestamp = g_ctimeDict->value( directoryFile, 0 );
+        const quint32 oldTimestamp = g_ctimeDict->ctime(directoryFile, g_resource);
 
         if (timeStamp && (timeStamp == oldTimestamp))
         {
@@ -353,7 +368,7 @@
             }
         }
      }
-     g_ctimeInfo->addCTime(directoryFile, timeStamp);
+     g_ctimeInfo->dict()->addCTime(directoryFile, g_resource, timeStamp);
 
      entry = g_buildServiceGroupFactory->addNew(subName, subMenu->directoryFile, \
entry, subMenu->isDeleted);  entry->setLayoutInfo(subMenu->layoutList);
@@ -701,8 +716,6 @@
      }
    }
 
-   g_changeList = new QStringList;
-
    bool checkstamps = incremental && args->isSet("checkstamps") && checkfiles;
    quint32 filestamp = 0;
    QStringList oldresourcedirs;
@@ -744,6 +757,7 @@
    }
 
    newTimestamp = (quint32) time(0);
+   QStringList changedResources;
 
    if( checkfiles && ( !checkstamps || !KBuildSycoca::checkTimestamps( filestamp, \
oldresourcedirs )))  {
@@ -758,7 +772,7 @@
          KSycoca::self();
          KSycocaFactoryList *factories = new KSycocaFactoryList;
          g_allEntries = new KSycocaEntryListList;
-         g_ctimeDict = new QHash<QString, quint32>;
+         g_ctimeDict = new KCTimeDict;
 
          // Must be in same order as in KBuildSycoca::recreate()!
          factories->append( new KServiceTypeFactory );
@@ -776,7 +790,7 @@
          }
          delete factories; factories = 0;
          KCTimeInfo *ctimeInfo = new KCTimeInfo;
-         ctimeInfo->fillCTimeDict(*g_ctimeDict);
+         *g_ctimeDict = ctimeInfo->loadDict();
       }
       cSycocaPath = 0;
 
@@ -786,6 +800,7 @@
       if (!sycoca->recreate()) {
         return -1;
       }
+      changedResources = sycoca->changedResources();
 
       if (bGlobalDatabase)
       {
@@ -802,10 +817,10 @@
    {
      // Notify ALL applications that have a ksycoca object, using a signal
      QDBusMessage signal = QDBusMessage::createSignal("/", "org.kde.KSycoca", \
                "notifyDatabaseChanged" );
-     signal << *g_changeList;
+     signal << changedResources;
 
      if (QDBusConnection::sessionBus().isConnected()) {
-        kDebug() << "Emitting notifyDatabaseChanged" << *g_changeList;
+         kDebug() << "Emitting notifyDatabaseChanged" << changedResources;
        QDBusConnection::sessionBus().send(signal);
        qApp->processEvents(); // make sure the dbus signal is sent before we quit.
      }
--- trunk/KDE/kdelibs/kded/kbuildsycoca.h #1200846:1200847
@@ -54,6 +54,8 @@
 
    void setTrackId(const QString &id) { m_trackId = id; }
 
+   QStringList changedResources() const { return m_changedResources; }
+
     // Use our friendly-access-to-KSycoca to make this public
     static void clearCaches() { KSycoca::clearCaches(); }
 
@@ -98,6 +100,7 @@
     */
    virtual bool isBuilding() { return true; }
 
+   QStringList m_changedResources;
    QStringList m_allResourceDirs;
    QString m_trackId;
 };
--- trunk/KDE/kdelibs/kded/kctimefactory.cpp #1200846:1200847
@@ -17,13 +17,78 @@
  **/
 
 #include "kctimefactory.h"
-#include "ksycoca.h"
-#include "ksycocatype.h"
+#include <ksycoca.h>
+#include <ksycocatype.h>
+#include <kdebug.h>
 
 #include <assert.h>
 
+static inline QString key(const QString &path, const QByteArray& resource)
+{
+    return QString::fromLatin1(resource) + QLatin1Char('|') + path;
+}
+
+void KCTimeDict::addCTime(const QString &path, const QByteArray& resource, quint32 \
ctime) +{
+    assert(!path.isEmpty());
+    m_hash.insert(key(path, resource), ctime );
+}
+
+quint32 KCTimeDict::ctime(const QString &path, const QByteArray& resource) const
+{
+    return m_hash.value(key(path, resource), 0);
+}
+
+void KCTimeDict::remove(const QString &path, const QByteArray &resource)
+{
+    m_hash.remove(key(path, resource));
+}
+
+void KCTimeDict::dump() const
+{
+    kDebug() << m_hash.keys();
+}
+
+QStringList KCTimeDict::resourceList() const
+{
+    QSet<QString> resources;
+    Hash::const_iterator it = m_hash.constBegin();
+    const Hash::const_iterator end = m_hash.constEnd();
+    for ( ; it != end; ++it ) {
+        const QString key = it.key();
+        const QString res = key.left(key.indexOf('|'));
+        resources.insert(res);
+    }
+    return resources.toList();
+}
+
+void KCTimeDict::load(QDataStream &str)
+{
+    QString key;
+    quint32 ctime;
+    while(true)
+    {
+        KSycocaEntry::read(str, key);
+        str >> ctime;
+        if (key.isEmpty()) break;
+        m_hash.insert(key, ctime);
+    }
+}
+
+void KCTimeDict::save(QDataStream &str) const
+{
+    Hash::const_iterator it = m_hash.constBegin();
+    const Hash::const_iterator end = m_hash.constEnd();
+    for ( ; it != end; ++it ) {
+       str << it.key() << it.value();
+    }
+    str << QString() << (quint32) 0;
+}
+
+///////////
+
 KCTimeInfo::KCTimeInfo()
-    : KSycocaFactory( KST_CTimeInfo ), ctimeDict()
+    : KSycocaFactory( KST_CTimeInfo ), m_ctimeDict()
 {
     if (!KSycoca::self()->isBuilding()) {
         QDataStream* str = stream();
@@ -45,52 +110,23 @@
   str << m_dictOffset;
 }
 
-void
-KCTimeInfo::save(QDataStream &str)
+void KCTimeInfo::save(QDataStream &str)
 {
   KSycocaFactory::save(str);
 
   m_dictOffset = str.device()->pos();
-  Dict::const_iterator it = ctimeDict.constBegin();
-  const Dict::const_iterator end = ctimeDict.constEnd();
-  for ( ; it != end; ++it )
-  {
-     str << it.key() << it.value();
-  }
-  str << QString() << (quint32) 0;
-
-  int endOfFactoryData = str.device()->pos();
-
+    m_ctimeDict.save(str);
+    const int endOfFactoryData = str.device()->pos();
   saveHeader(str);
   str.device()->seek(endOfFactoryData);
 }
 
-void
-KCTimeInfo::addCTime(const QString &path, quint32 ctime)
+KCTimeDict KCTimeInfo::loadDict() const
 {
-  assert(!path.isEmpty());
-  ctimeDict.insert(path, ctime);
-}
-
-quint32
-KCTimeInfo::ctime(const QString &path)
-{
-  return ctimeDict.value( path, 0 );
-}
-
-void
-KCTimeInfo::fillCTimeDict(Dict &dict)
-{
+    KCTimeDict dict;
     QDataStream* str = stream();
     assert(str);
     str->device()->seek(m_dictOffset);
-    QString path;
-    quint32 ctime;
-    while(true)
-    {
-      KSycocaEntry::read(*str, path);
-      (*str) >> ctime;
-      if (path.isEmpty()) break;
-      dict.insert(path, ctime);
+    dict.load(*str);
+    return dict;
     }
-}
--- trunk/KDE/kdelibs/kded/kctimefactory.h #1200846:1200847
@@ -23,10 +23,30 @@
 #include <QtCore/QHash>
 
 /**
- * Service group factory for building ksycoca
+ * Simple dict for assocating a timestamp with each file in ksycoca
+ */
+class KCTimeDict
+{
+public:
+    void addCTime(const QString &path, const QByteArray& resource, quint32 ctime);
+    quint32 ctime(const QString &path, const QByteArray& resource) const;
+    void remove(const QString &path, const QByteArray& resource);
+    void dump() const;
+    bool isEmpty() const { return m_hash.isEmpty(); }
+    QStringList resourceList() const;
+
+    void load(QDataStream &str);
+    void save(QDataStream &str) const;
+private:
+    typedef QHash<QString, quint32> Hash;
+    Hash m_hash;
+};
+
+/**
+ * Internal factory for storing the timestamp of each file in ksycoca
  * @internal
  */
-class KCTimeInfo : public KSycocaFactory
+class KCTimeInfo : public KSycocaFactory // TODO rename to KCTimeFactory
 {
   K_SYCOCAFACTORY( KST_CTimeInfo )
 public:
@@ -50,15 +70,15 @@
   KSycocaEntry * createEntry(const QString &, const char *) const { return 0; }
   KSycocaEntry * createEntry(int) const { return 0; }
 
-  void addCTime(const QString &path, quint32 ctime);
+  // Loads the dict and returns it; does not set m_ctimeDict;
+  // this is only used in incremental mode for loading the old timestamps.
+  KCTimeDict loadDict() const;
 
-  quint32 ctime(const QString &path);
+  // The API for inserting/looking up entries is in KCTimeDict.
+  KCTimeDict* dict() { return &m_ctimeDict; }
 
-  typedef QHash<QString, quint32> Dict;
-  void fillCTimeDict(Dict &dict);
-
-protected:
-  Dict ctimeDict;
+private:
+  KCTimeDict m_ctimeDict;
   int m_dictOffset;
 };
 


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic