Version: (using KDE KDE 3.4.0) Installed from: Compiled From Sources Compiler: gcc 3.3.3 cygwin special OS: Cygwin I get this error while updating or adding an entry in the menu using kmenuedit: kbuildsycoca: ERROR writing database '/var/tmp/kdecache-sunil/ksycoca'! kbuildsycoca: Disk full? Basically this is what is going on inside of kbuildsycoca: the problem with updating ksycoca database is coming from database.close() line in kbuildsycoca.cpp : if (!database.close()) { fprintf(stderr, "kbuildsycoca: ERROR writing database '%s'!\n",database.name().local8Bit().data()); fprintf(stderr, "kbuildsycoca: Disk full?\n"); #ifdef KBUILDSYCOCA_GUI if (!silent) KMessageBox::error(0, i18n("Error writing database '%1'.\nCheck that the permissions are correct on the directory and the disk is not full.\n").arg(path.local8Bit().data()),i18n("KBuildSycoca")); #endif return false; } kdecore/ksavefile.cpp has the following piece of code where close() renames the temporary file to the ksycoca in /var/tmp/kdecache-<username>/. This fails because some process has opened that file READ_ONLY. cygwin/windows doesn't allow overwriting a file which is open in another process. It looks like it is kded daemon as one of processes which has it opened. But I am not sure how to ask these processes to close this file. if (mTempFile.close()) { if (0==KDE_rename(QFile::encodeName(mTempFile.name()),QFile::encodeName(mFileName))) return true; // Success! mTempFile.setError(errno); } this is where processes open the ksycoca database in kdecore/ksycoca.cpp: kdDebug(7011) << "Trying to open ksycoca from " << path << endl; QFile *database = new QFile(path); bool bOpen = database->open( IO_ReadOnly ); I am not sure how to tackle this. In Unix its so easy to assume that readers won't stop writers from writing. I think cygwin needs different semantics, wherein its the kded which does the update to the database always (currently eny process can call kbuildsycoca to update the database) and everybody, who has the database opened, is asked to close the database before rename() is issued by kded?
following comes from Ralf on kde-cygwin list, and its more detailed: -------------------------------------------------------------------------------- all access to the ksycoca database is encapsulated by the class KSycoca, which contains a signal handler notifyDatabaseChanged(), wich closes the database. from kdecore/ksycoca.cpp void KSycoca::notifyDatabaseChanged(const QStringList &changeList) { d->changeList = changeList; //kdDebug(7011) << "got a notifyDatabaseChanged signal !" << endl; // kded tells us the database file changed // Close the database and forget all about what we knew // The next call to any public method will recreate // everything that's needed. closeDatabase(); // Now notify applications emit databaseChanged(); } The relating signal is send after updating the database in kbuildsycoca:kdemain(): if (args->isSet("signal")) { // Notify ALL applications that have a ksycoca object, using a broadcast QByteArray data; QDataStream stream(data, IO_WriteOnly); stream << *g_changeList; dcopClient->send( "*", "ksycoca", "notifyDatabaseChanged(QStringList)", data ); } The problem is that this signal is send to late. A workaround could be to send this signal immediatly before the call to KBuildSycoca::recreate() in kbuildsycoca:kdemain() KBuildSycoca *sycoca= new KBuildSycoca; // Build data base if (args->isSet("track")) sycoca->setTrackId(QString::fromLocal8Bit(args->getOption("track"))); >>>>>>>>>>>>>>>>>>>> if (args->isSet("signal")) { // Notify ALL applications that have a ksycoca object, using a broadcast QByteArray data; QDataStream stream(data, IO_WriteOnly); stream << *g_changeList; dcopClient->send( "*", "ksycoca", "notifyDatabaseChanged(QStringList)", data ); } <<<<<<<<<<<<<<<<<<< if (!sycoca->recreate()) { but I don't do if this works in any cases. A generic approach is to introduce a new signal for example notifyDatabaseUpdatePending or so, which could close and lock any unwanted access to the database until the notifyDatabaseChanged is send. If the workaround doesn't work we can implemented this. -------------------------------------------------------------------------------
notifyDatabaseUpdatePending would need to call all clients one-by-one and wait for each call to return. Even then it's still not guaranteed to work. Whatever solution you come up with, please do not change the behavior under unix.
what is the right solution in your mind then?
> notifyDatabaseUpdatePending would need to call all clients one-by-one and wait for each call to return. This could be done by using the synchronous call() method instead of the asynchronous send(). Unfortunally call() could not send the messages to all related applications instead The applications has to be enumerated. Currently I don't know which dcop function could be used. Any hints ? >Even then it's still not guaranteed to work. Why
You can use DCOPClient::registeredApplications() to get a list of all apps. > >Even then it's still not guaranteed to work. > Why A new application can start in the mean time and open the database.
> A new application can start in the mean time and open the database. I don't thoughed about What about if kbuildsycoca would update the database, rename it to a new (unused) name, store the name in a configfile and send all related applications the new name for updating their database ? I saw that the name is currently hardcoded in from kdecore/ksycoca.cpp -- path = KGlobal::dirs()->saveLocation("cache") + "ksycoca";
For the record: One problem is that kio_xxx processes does not have a dcop instance and does not handle dcop signals, so they don't got any notice about the ksycoca database change :-(.
> they don't got any notice about the ksycoca database change One question: is this a feature or a whole in the design ?
this is what I did temporarily. Basically, close the database in all before recreate and execute normally. hopefully recreate() takes long enough before issuing rename() that existing apps can close() and but short enough that no other application comes along to open the database. This doesn't solve the problem in all corner cases. ------------------------------------------------------------- $ diff -u kdecore/ksycoca.kidl.orig kdecore/ksycoca.kidl --- kdecore/ksycoca.kidl.orig 2005-05-14 15:48:22.000000000 -0700 +++ kdecore/ksycoca.kidl 2005-05-14 15:59:08.000000000 -0700 @@ -12,6 +12,10 @@ <SUPER>DCOPObject</SUPER> <FUNC> <TYPE>void</TYPE> + <NAME>closeDatabase</NAME> + </FUNC> + <FUNC> + <TYPE>void</TYPE> <NAME>notifyDatabaseChanged</NAME> <ARG><TYPE qleft="const" qright="&">QStringList</TYPE></ARG> </FUNC> $ diff -u kded/kbuildsycoca.cpp.orig kded/kbuildsycoca.cpp --- kded/kbuildsycoca.cpp.orig 2005-05-14 15:34:28.000000000 -0700 +++ kded/kbuildsycoca.cpp 2005-05-14 16:02:20.000000000 -0700 @@ -908,6 +908,13 @@ KBuildSycoca *sycoca= new KBuildSycoca; // Build data base if (args->isSet("track")) sycoca->setTrackId(QString::fromLocal8Bit(args->getOption("track"))); + + if (args->isSet("signal")) + { + // Notify ALL applications that have a ksycoca object, using a broadcast + dcopClient->send( "*", "ksycoca", "closeDatabase()", ""); + } + if (!sycoca->recreate()) { #ifdef KBUILDSYCOCA_GUI if (!silent || showprogress) ------------------------------------
Still relevant to recent KDE version? If not please close the bug. Thanks, Lex.
ksycoca uses shared memory on Windows these days, this problem is long gone.