EDS Client: handle "busy" error

In EDS 3.6.4, opening fails a lot more often with E_CLIENT_ERROR_BUSY.
We must retry until we succeed.

Seen in particular with testpim.py testFilterStartup. Clients are expected to
try the open call again. EDS >= 3.8 does that automatically.
This commit is contained in:
Patrick Ohly 2013-04-02 07:36:21 -07:00
parent 065fdcd343
commit e3f0a297f7
2 changed files with 59 additions and 28 deletions

View file

@ -89,19 +89,25 @@ EClientCXX EvolutionSyncSource::openESource(const char *extension,
(void *)"Evolution Data Server has died unexpectedly.");
// Always allow EDS to create the database. "only-if-exists =
// true" does not make sense.
if (!e_client_open_sync(client, false, NULL, gerror)) {
if (created) {
// Opening newly created address books often failed in old
// EDS releases - try again.
gerror.clear();
sleep(5);
if (!e_client_open_sync(client, false, NULL, gerror)) {
while (true) {
// Always allow EDS to create the database. "only-if-exists =
// true" does not make sense.
if (!e_client_open_sync(client, false, NULL, gerror)) {
if (gerror && g_error_matches(gerror, E_CLIENT_ERROR, E_CLIENT_ERROR_BUSY)) {
gerror.clear();
sleep(1);
} else if (created) {
// Opening newly created address books often failed in
// old EDS releases - try again. Probably covered by
// more recently added E_CLIENT_ERROR_BUSY check above.
gerror.clear();
sleep(5);
} else {
throwError("opening database", gerror);
}
} else {
throwError("opening database", gerror);
// Success!
break;
}
}

View file

@ -49,6 +49,8 @@ boost::shared_ptr<EDSFView> EDSFView::create(const ESourceRegistryCXX &registry,
void EDSFView::doStart()
{
// This function may get entered again, see retry code in opened() below.
ESourceCXX source(e_source_registry_ref_source(m_registry, m_uuid.c_str()), false);
if (!source) {
SE_LOG_DEBUG(NULL, NULL, "edsf %s: address book not found", m_uuid.c_str());
@ -56,23 +58,36 @@ void EDSFView::doStart()
}
m_store = EdsfPersonaStoreCXX::steal(edsf_persona_store_new_with_source_registry(m_registry, source));
GErrorCXX gerror;
m_ebook = EBookClientCXX::steal(
#ifdef HAVE_E_BOOK_CLIENT_NEW_DIRECT
getenv("SYNCEVOLUTION_NO_PIM_EDS_DIRECT") ?
e_book_client_new(source, gerror) :
e_book_client_new_direct(m_registry, source, gerror)
#elif defined(HAVE_E_BOOK_CLIENT_CONNECT_DIRECT_SYNC)
getenv("SYNCEVOLUTION_NO_PIM_EDS_DIRECT") ?
e_book_client_new(source, gerror) :
E_BOOK_CLIENT(e_book_client_connect_direct_sync(m_registry, source, NULL, gerror))
#else
e_book_client_new(source, gerror)
#endif
);
if (!m_ebook) {
SE_LOG_DEBUG(NULL, NULL, "edfs %s: no client for address book: %s", m_uuid.c_str(), gerror->message);
#ifdef HAVE_E_BOOK_CLIENT_CONNECT_DIRECT_SYNC
// TODO: use asynchronous version, once there is one in EDS
if (!getenv("SYNCEVOLUTION_NO_PIM_EDS_DIRECT")) {
while (!m_ebook) {
SE_LOG_DEBUG(NULL, NULL, "edsf %s: synchronously connecting direct", m_uuid.c_str());
m_ebook = EBookClientCXX::steal(E_BOOK_CLIENT(e_book_client_connect_direct_sync(m_registry, source, NULL, gerror)));
if (!m_ebook) {
SE_LOG_DEBUG(NULL, NULL, "edsf %s: no DRA client for address book: %s", m_uuid.c_str(), gerror ? gerror->message : "???");
if (gerror && g_error_matches(gerror, E_CLIENT_ERROR, E_CLIENT_ERROR_BUSY)) {
SE_LOG_DEBUG(NULL, NULL, "edsf %s: try again", m_uuid.c_str());
gerror.clear();
} else {
return;
}
}
}
// Already opened by call above, proceed immediately.
opened(true, NULL);
return;
}
#endif
SE_LOG_DEBUG(NULL, NULL, "edsf %s: new client", m_uuid.c_str());
m_ebook = EBookClientCXX::steal(e_book_client_new(source, gerror));
if (!m_ebook) {
SE_LOG_DEBUG(NULL, NULL, "edsf %s: no normal client for address book: %s", m_uuid.c_str(), gerror ? gerror->message : "???");
return;
}
SE_LOG_DEBUG(NULL, NULL, "edsf %s: asynchronous open", m_uuid.c_str());
SYNCEVO_GLIB_CALL_ASYNC(e_client_open,
boost::bind(&EDSFView::opened,
m_self,
@ -87,9 +102,14 @@ void EDSFView::opened(gboolean success, const GError *gerror) throw()
{
try {
if (!success) {
SE_LOG_DEBUG(NULL, NULL, "edfs %s: opening failed: %s", m_uuid.c_str(), gerror->message);
return;
SE_LOG_DEBUG(NULL, NULL, "edsf %s: opening failed: %s", m_uuid.c_str(), gerror ? gerror->message : "???");
if (gerror && g_error_matches(gerror, E_CLIENT_ERROR, E_CLIENT_ERROR_BUSY)) {
SE_LOG_DEBUG(NULL, NULL, "edsf %s: try again", m_uuid.c_str());
doStart();
return;
}
}
SE_LOG_DEBUG(NULL, NULL, "edsf %s: opened successfully, reading contacts asynchronously: %s", m_uuid.c_str(), m_query.c_str());
SYNCEVO_GLIB_CALL_ASYNC(e_book_client_get_contacts,
boost::bind(&EDSFView::read,
m_self,
@ -107,9 +127,14 @@ void EDSFView::opened(gboolean success, const GError *gerror) throw()
void EDSFView::read(gboolean success, GSList *contactslist, const GError *gerror) throw()
{
try {
SE_LOG_DEBUG(NULL, NULL, "edsf %s: reading contacts completed: %s",
m_uuid.c_str(),
success ? "success" :
gerror ? gerror->message :
"failed without error");
GListCXX<EContact, GSList, GObjectDestructor> contacts(contactslist);
if (!success) {
SE_LOG_DEBUG(NULL, NULL, "edfs %s: reading failed: %s", m_uuid.c_str(), gerror->message);
SE_LOG_DEBUG(NULL, NULL, "edsf %s: reading failed: %s", m_uuid.c_str(), gerror->message);
return;
}