[evolution-data-server] EDataCal: Queue operations while opening.



commit 12821b5f56a684a3f31d47a160d67851c04d08b1
Author: Matthew Barnes <mbarnes redhat com>
Date:   Wed Jan 23 12:09:10 2013 -0500

    EDataCal: Queue operations while opening.
    
    When an open operation is in progress, queue any subsequent operations
    and dispatch them after the current open operation is complete.
    
    The old behavior returned a BUSY error and forced the client to retry.
    Clients are not involved in authentication anymore, so they should not
    have to retry operations nor worry about whether the backend is opened.
    
    This should really be handled directly by ECalBackend, but because of
    the weird async semantics between ECalBackend and EDataCal, the queue
    needs to live in EDataCal for now.

 calendar/libedata-cal/e-cal-backend.c |   99 ++++++++++++++++++---------------
 calendar/libedata-cal/e-data-cal.c    |   83 +++++++++++++++++++++++-----
 2 files changed, 124 insertions(+), 58 deletions(-)
---
diff --git a/calendar/libedata-cal/e-cal-backend.c b/calendar/libedata-cal/e-cal-backend.c
index 508fd5a..efce8ad 100644
--- a/calendar/libedata-cal/e-cal-backend.c
+++ b/calendar/libedata-cal/e-cal-backend.c
@@ -33,7 +33,6 @@
 	((obj), E_TYPE_CAL_BACKEND, ECalBackendPrivate))
 
 #define EDC_ERROR(_code)	e_data_cal_create_error (_code, NULL)
-#define EDC_OPENING_ERROR	e_data_cal_create_error (Busy, _("Cannot process, calendar backend is opening"))
 #define EDC_NOT_OPENED_ERROR	e_data_cal_create_error (NotOpened, NULL)
 
 /* Private part of the CalBackend structure */
@@ -1101,6 +1100,9 @@ e_cal_backend_open (ECalBackend *backend,
 	g_return_if_fail (E_IS_CAL_BACKEND (backend));
 	g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->open != NULL);
 
+	/* This should never be called while we're opening. */
+	g_return_if_fail (!e_cal_backend_is_opening (backend));
+
 	g_mutex_lock (&backend->priv->clients_mutex);
 
 	if (e_cal_backend_is_opened (backend)) {
@@ -1114,10 +1116,6 @@ e_cal_backend_open (ECalBackend *backend,
 		e_data_cal_report_online (cal, online);
 
 		e_cal_backend_respond_opened (backend, cal, opid, NULL);
-	} else if (e_cal_backend_is_opening (backend)) {
-		g_mutex_unlock (&backend->priv->clients_mutex);
-
-		e_data_cal_respond_open (cal, opid, EDC_OPENING_ERROR);
 	} else {
 		backend->priv->opening = TRUE;
 		g_mutex_unlock (&backend->priv->clients_mutex);
@@ -1151,9 +1149,10 @@ e_cal_backend_refresh (ECalBackend *backend,
 	g_return_if_fail (backend != NULL);
 	g_return_if_fail (E_IS_CAL_BACKEND (backend));
 
-	if (e_cal_backend_is_opening (backend))
-		e_data_cal_respond_refresh (cal, opid, EDC_OPENING_ERROR);
-	else if (!E_CAL_BACKEND_GET_CLASS (backend)->refresh)
+	/* This should never be called while we're opening. */
+	g_return_if_fail (!e_cal_backend_is_opening (backend));
+
+	if (!E_CAL_BACKEND_GET_CLASS (backend)->refresh)
 		e_data_cal_respond_refresh (cal, opid, EDC_ERROR (UnsupportedMethod));
 	else if (!e_cal_backend_is_opened (backend))
 		e_data_cal_respond_refresh (cal, opid, EDC_NOT_OPENED_ERROR);
@@ -1187,9 +1186,10 @@ e_cal_backend_get_object (ECalBackend *backend,
 	g_return_if_fail (uid != NULL);
 	g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_object != NULL);
 
-	if (e_cal_backend_is_opening (backend))
-		e_data_cal_respond_get_object (cal, opid, EDC_OPENING_ERROR, NULL);
-	else if (!e_cal_backend_is_opened (backend))
+	/* This should never be called while we're opening. */
+	g_return_if_fail (!e_cal_backend_is_opening (backend));
+
+	if (!e_cal_backend_is_opened (backend))
 		e_data_cal_respond_get_object (cal, opid, EDC_NOT_OPENED_ERROR, NULL);
 	else
 		(* E_CAL_BACKEND_GET_CLASS (backend)->get_object) (backend, cal, opid, cancellable, uid, rid);
@@ -1217,9 +1217,10 @@ e_cal_backend_get_object_list (ECalBackend *backend,
 	g_return_if_fail (E_IS_CAL_BACKEND (backend));
 	g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_object_list != NULL);
 
-	if (e_cal_backend_is_opening (backend))
-		e_data_cal_respond_get_object_list (cal, opid, EDC_OPENING_ERROR, NULL);
-	else if (!e_cal_backend_is_opened (backend))
+	/* This should never be called while we're opening. */
+	g_return_if_fail (!e_cal_backend_is_opening (backend));
+
+	if (!e_cal_backend_is_opened (backend))
 		e_data_cal_respond_get_object_list (cal, opid, EDC_NOT_OPENED_ERROR, NULL);
 	else
 		(* E_CAL_BACKEND_GET_CLASS (backend)->get_object_list) (backend, cal, opid, cancellable, sexp);
@@ -1254,9 +1255,10 @@ e_cal_backend_get_free_busy (ECalBackend *backend,
 	g_return_if_fail (start <= end);
 	g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_free_busy != NULL);
 
-	if (e_cal_backend_is_opening (backend))
-		e_data_cal_respond_get_free_busy (cal, opid, EDC_OPENING_ERROR);
-	else if (!e_cal_backend_is_opened (backend))
+	/* This should never be called while we're opening. */
+	g_return_if_fail (!e_cal_backend_is_opening (backend));
+
+	if (!e_cal_backend_is_opened (backend))
 		e_data_cal_respond_get_free_busy (cal, opid, EDC_NOT_OPENED_ERROR);
 	else
 		(* E_CAL_BACKEND_GET_CLASS (backend)->get_free_busy) (backend, cal, opid, cancellable, users, start, end);
@@ -1286,9 +1288,10 @@ e_cal_backend_create_objects (ECalBackend *backend,
 	g_return_if_fail (E_IS_CAL_BACKEND (backend));
 	g_return_if_fail (calobjs != NULL);
 
-	if (e_cal_backend_is_opening (backend))
-		e_data_cal_respond_create_objects (cal, opid, EDC_OPENING_ERROR, NULL, NULL);
-	else if (!E_CAL_BACKEND_GET_CLASS (backend)->create_objects)
+	/* This should never be called while we're opening. */
+	g_return_if_fail (!e_cal_backend_is_opening (backend));
+
+	if (!E_CAL_BACKEND_GET_CLASS (backend)->create_objects)
 		e_data_cal_respond_create_objects (cal, opid, EDC_ERROR (UnsupportedMethod), NULL, NULL);
 	else if (!e_cal_backend_is_opened (backend))
 		e_data_cal_respond_create_objects (cal, opid, EDC_NOT_OPENED_ERROR, NULL, NULL);
@@ -1322,9 +1325,10 @@ e_cal_backend_modify_objects (ECalBackend *backend,
 	g_return_if_fail (E_IS_CAL_BACKEND (backend));
 	g_return_if_fail (calobjs != NULL);
 
-	if (e_cal_backend_is_opening (backend))
-		e_data_cal_respond_modify_objects (cal, opid, EDC_OPENING_ERROR, NULL, NULL);
-	else if (!E_CAL_BACKEND_GET_CLASS (backend)->modify_objects)
+	/* This should never be called while we're opening. */
+	g_return_if_fail (!e_cal_backend_is_opening (backend));
+
+	if (!E_CAL_BACKEND_GET_CLASS (backend)->modify_objects)
 		e_data_cal_respond_modify_objects (cal, opid, EDC_ERROR (UnsupportedMethod), NULL, NULL);
 	else if (!e_cal_backend_is_opened (backend))
 		e_data_cal_respond_modify_objects (cal, opid, EDC_NOT_OPENED_ERROR, NULL, NULL);
@@ -1360,9 +1364,10 @@ e_cal_backend_remove_objects (ECalBackend *backend,
 	g_return_if_fail (ids != NULL);
 	g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->remove_objects != NULL);
 
-	if (e_cal_backend_is_opening (backend))
-		e_data_cal_respond_remove_objects (cal, opid, EDC_OPENING_ERROR, NULL, NULL, NULL);
-	else if (!e_cal_backend_is_opened (backend))
+	/* This should never be called while we're opening. */
+	g_return_if_fail (!e_cal_backend_is_opening (backend));
+
+	if (!e_cal_backend_is_opened (backend))
 		e_data_cal_respond_remove_objects (cal, opid, EDC_NOT_OPENED_ERROR, NULL, NULL, NULL);
 	else
 		(* E_CAL_BACKEND_GET_CLASS (backend)->remove_objects) (backend, cal, opid, cancellable, ids, mod);
@@ -1391,9 +1396,10 @@ e_cal_backend_receive_objects (ECalBackend *backend,
 	g_return_if_fail (calobj != NULL);
 	g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->receive_objects != NULL);
 
-	if (e_cal_backend_is_opening (backend))
-		e_data_cal_respond_receive_objects (cal, opid, EDC_OPENING_ERROR);
-	else if (!e_cal_backend_is_opened (backend))
+	/* This should never be called while we're opening. */
+	g_return_if_fail (!e_cal_backend_is_opening (backend));
+
+	if (!e_cal_backend_is_opened (backend))
 		e_data_cal_respond_receive_objects (cal, opid, EDC_NOT_OPENED_ERROR);
 	else
 		(* E_CAL_BACKEND_GET_CLASS (backend)->receive_objects) (backend, cal, opid, cancellable, calobj);
@@ -1422,9 +1428,10 @@ e_cal_backend_send_objects (ECalBackend *backend,
 	g_return_if_fail (calobj != NULL);
 	g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->send_objects != NULL);
 
-	if (e_cal_backend_is_opening (backend))
-		e_data_cal_respond_send_objects (cal, opid, EDC_OPENING_ERROR, NULL, NULL);
-	else if (!e_cal_backend_is_opened (backend))
+	/* This should never be called while we're opening. */
+	g_return_if_fail (!e_cal_backend_is_opening (backend));
+
+	if (!e_cal_backend_is_opened (backend))
 		e_data_cal_respond_send_objects (cal, opid, EDC_NOT_OPENED_ERROR, NULL, NULL);
 	else
 		(* E_CAL_BACKEND_GET_CLASS (backend)->send_objects) (backend, cal, opid, cancellable, calobj);
@@ -1458,9 +1465,10 @@ e_cal_backend_get_attachment_uris (ECalBackend *backend,
 	g_return_if_fail (uid != NULL);
 	g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_attachment_uris != NULL);
 
-	if (e_cal_backend_is_opening (backend))
-		e_data_cal_respond_get_attachment_uris (cal, opid, EDC_OPENING_ERROR, NULL);
-	else if (!e_cal_backend_is_opened (backend))
+	/* This should never be called while we're opening. */
+	g_return_if_fail (!e_cal_backend_is_opening (backend));
+
+	if (!e_cal_backend_is_opened (backend))
 		e_data_cal_respond_get_attachment_uris (cal, opid, EDC_NOT_OPENED_ERROR, NULL);
 	else
 		(* E_CAL_BACKEND_GET_CLASS (backend)->get_attachment_uris) (backend, cal, opid, cancellable, uid, rid);
@@ -1494,9 +1502,10 @@ e_cal_backend_discard_alarm (ECalBackend *backend,
 	g_return_if_fail (uid != NULL);
 	g_return_if_fail (auid != NULL);
 
-	if (e_cal_backend_is_opening (backend))
-		e_data_cal_respond_discard_alarm (cal, opid, EDC_OPENING_ERROR);
-	else if (!E_CAL_BACKEND_GET_CLASS (backend)->discard_alarm)
+	/* This should never be called while we're opening. */
+	g_return_if_fail (!e_cal_backend_is_opening (backend));
+
+	if (!E_CAL_BACKEND_GET_CLASS (backend)->discard_alarm)
 		e_data_cal_respond_discard_alarm (cal, opid, e_data_cal_create_error (NotSupported, NULL));
 	else if (!e_cal_backend_is_opened (backend))
 		e_data_cal_respond_discard_alarm (cal, opid, EDC_NOT_OPENED_ERROR);
@@ -1529,9 +1538,10 @@ e_cal_backend_get_timezone (ECalBackend *backend,
 	g_return_if_fail (tzid != NULL);
 	g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_timezone != NULL);
 
-	if (e_cal_backend_is_opening (backend))
-		e_data_cal_respond_get_timezone (cal, opid, EDC_OPENING_ERROR, NULL);
-	else if (!e_cal_backend_is_opened (backend))
+	/* This should never be called while we're opening. */
+	g_return_if_fail (!e_cal_backend_is_opening (backend));
+
+	if (!e_cal_backend_is_opened (backend))
 		e_data_cal_respond_get_timezone (cal, opid, EDC_NOT_OPENED_ERROR, NULL);
 	else
 		(* E_CAL_BACKEND_GET_CLASS (backend)->get_timezone) (backend, cal, opid, cancellable, tzid);
@@ -1559,9 +1569,10 @@ e_cal_backend_add_timezone (ECalBackend *backend,
 	g_return_if_fail (tzobject != NULL);
 	g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->add_timezone != NULL);
 
-	if (e_cal_backend_is_opening (backend))
-		e_data_cal_respond_add_timezone (cal, opid, EDC_OPENING_ERROR);
-	else if (!e_cal_backend_is_opened (backend))
+	/* This should never be called while we're opening. */
+	g_return_if_fail (!e_cal_backend_is_opening (backend));
+
+	if (!e_cal_backend_is_opened (backend))
 		e_data_cal_respond_add_timezone (cal, opid, EDC_NOT_OPENED_ERROR);
 	else
 		(* E_CAL_BACKEND_GET_CLASS (backend)->add_timezone) (backend, cal, opid, cancellable, tzobject);
diff --git a/calendar/libedata-cal/e-data-cal.c b/calendar/libedata-cal/e-data-cal.c
index 1b0f9d3..3bfda4e 100644
--- a/calendar/libedata-cal/e-data-cal.c
+++ b/calendar/libedata-cal/e-data-cal.c
@@ -52,6 +52,12 @@ struct _EDataCalPrivate {
 
 	GRecMutex pending_ops_lock;
 	GHashTable *pending_ops; /* opid to GCancellable for still running operations */
+
+	/* Operations are queued while an
+	 * open operation is in progress. */
+	GMutex open_lock;
+	guint32 open_opid;
+	GQueue open_queue;
 };
 
 enum {
@@ -354,6 +360,25 @@ op_new (OperationID op,
 }
 
 static void
+op_dispatch (EDataCal *cal,
+             OperationData *data)
+{
+	g_mutex_lock (&cal->priv->open_lock);
+
+	/* If an open operation is currently in progress, queue this
+	 * operation to be dispatched when the open operation finishes. */
+	if (cal->priv->open_opid > 0) {
+		g_queue_push_tail (&cal->priv->open_queue, data);
+	} else {
+		if (data->op == OP_OPEN)
+			cal->priv->open_opid = data->id;
+		e_operation_pool_push (ops_pool, data);
+	}
+
+	g_mutex_unlock (&cal->priv->open_lock);
+}
+
+static void
 op_complete (EDataCal *cal,
              guint32 opid)
 {
@@ -528,7 +553,7 @@ impl_Cal_open (EGdbusCal *interface,
 
 	e_gdbus_cal_complete_open (interface, invocation, op->id);
 
-	e_operation_pool_push (ops_pool, op);
+	op_dispatch (cal, op);
 
 	return TRUE;
 }
@@ -544,7 +569,7 @@ impl_Cal_refresh (EGdbusCal *interface,
 
 	e_gdbus_cal_complete_refresh (interface, invocation, op->id);
 
-	e_operation_pool_push (ops_pool, op);
+	op_dispatch (cal, op);
 
 	return TRUE;
 }
@@ -562,6 +587,7 @@ impl_Cal_get_backend_property (EGdbusCal *interface,
 
 	e_gdbus_cal_complete_get_backend_property (interface, invocation, op->id);
 
+	/* This operation is never queued. */
 	e_operation_pool_push (ops_pool, op);
 
 	return TRUE;
@@ -580,6 +606,7 @@ impl_Cal_set_backend_property (EGdbusCal *interface,
 
 	e_gdbus_cal_complete_set_backend_property (interface, invocation, op->id);
 
+	/* This operation is never queued. */
 	e_operation_pool_push (ops_pool, op);
 
 	return TRUE;
@@ -598,7 +625,7 @@ impl_Cal_get_object (EGdbusCal *interface,
 
 	e_gdbus_cal_complete_get_object (interface, invocation, op->id);
 
-	e_operation_pool_push (ops_pool, op);
+	op_dispatch (cal, op);
 
 	return TRUE;
 }
@@ -616,7 +643,7 @@ impl_Cal_get_object_list (EGdbusCal *interface,
 
 	e_gdbus_cal_complete_get_object_list (interface, invocation, op->id);
 
-	e_operation_pool_push (ops_pool, op);
+	op_dispatch (cal, op);
 
 	return TRUE;
 }
@@ -638,7 +665,7 @@ impl_Cal_get_free_busy (EGdbusCal *interface,
 
 	e_gdbus_cal_complete_get_free_busy (interface, invocation, op->id);
 
-	e_operation_pool_push (ops_pool, op);
+	op_dispatch (cal, op);
 
 	return TRUE;
 }
@@ -656,7 +683,7 @@ impl_Cal_create_objects (EGdbusCal *interface,
 
 	e_gdbus_cal_complete_create_objects (interface, invocation, op->id);
 
-	e_operation_pool_push (ops_pool, op);
+	op_dispatch (cal, op);
 
 	return TRUE;
 }
@@ -676,7 +703,7 @@ impl_Cal_modify_objects (EGdbusCal *interface,
 
 	e_gdbus_cal_complete_modify_objects (interface, invocation, op->id);
 
-	e_operation_pool_push (ops_pool, op);
+	op_dispatch (cal, op);
 
 	return TRUE;
 }
@@ -696,7 +723,7 @@ impl_Cal_remove_objects (EGdbusCal *interface,
 
 	e_gdbus_cal_complete_remove_objects (interface, invocation, op->id);
 
-	e_operation_pool_push (ops_pool, op);
+	op_dispatch (cal, op);
 
 	return TRUE;
 }
@@ -714,7 +741,7 @@ impl_Cal_receive_objects (EGdbusCal *interface,
 
 	e_gdbus_cal_complete_receive_objects (interface, invocation, op->id);
 
-	e_operation_pool_push (ops_pool, op);
+	op_dispatch (cal, op);
 
 	return TRUE;
 }
@@ -732,7 +759,7 @@ impl_Cal_send_objects (EGdbusCal *interface,
 
 	e_gdbus_cal_complete_send_objects (interface, invocation, op->id);
 
-	e_operation_pool_push (ops_pool, op);
+	op_dispatch (cal, op);
 
 	return TRUE;
 }
@@ -750,7 +777,7 @@ impl_Cal_get_attachment_uris (EGdbusCal *interface,
 
 	e_gdbus_cal_complete_get_attachment_uris (interface, invocation, op->id);
 
-	e_operation_pool_push (ops_pool, op);
+	op_dispatch (cal, op);
 
 	return TRUE;
 }
@@ -768,7 +795,7 @@ impl_Cal_discard_alarm (EGdbusCal *interface,
 
 	e_gdbus_cal_complete_discard_alarm (interface, invocation, op->id);
 
-	e_operation_pool_push (ops_pool, op);
+	op_dispatch (cal, op);
 
 	return TRUE;
 }
@@ -786,6 +813,7 @@ impl_Cal_get_view (EGdbusCal *interface,
 
 	e_gdbus_cal_complete_get_view (interface, invocation, op->id);
 
+	/* This operation is never queued. */
 	e_operation_pool_push (ops_pool, op);
 
 	return TRUE;
@@ -804,7 +832,7 @@ impl_Cal_get_timezone (EGdbusCal *interface,
 
 	e_gdbus_cal_complete_get_timezone (interface, invocation, op->id);
 
-	e_operation_pool_push (ops_pool, op);
+	op_dispatch (cal, op);
 
 	return TRUE;
 }
@@ -822,7 +850,7 @@ impl_Cal_add_timezone (EGdbusCal *interface,
 
 	e_gdbus_cal_complete_add_timezone (interface, invocation, op->id);
 
-	e_operation_pool_push (ops_pool, op);
+	op_dispatch (cal, op);
 
 	return TRUE;
 }
@@ -840,6 +868,7 @@ impl_Cal_cancel_operation (EGdbusCal *interface,
 
 	e_gdbus_cal_complete_cancel_operation (interface, invocation, NULL);
 
+	/* This operation is never queued. */
 	e_operation_pool_push (ops_pool, op);
 
 	return TRUE;
@@ -856,6 +885,7 @@ impl_Cal_cancel_all (EGdbusCal *interface,
 
 	e_gdbus_cal_complete_cancel_all (interface, invocation, NULL);
 
+	/* This operation is never queued. */
 	e_operation_pool_push (ops_pool, op);
 
 	return TRUE;
@@ -874,6 +904,7 @@ impl_Cal_close (EGdbusCal *interface,
 
 	e_gdbus_cal_complete_close (interface, invocation, NULL);
 
+	/* This operation is never queued. */
 	e_operation_pool_push (ops_pool, op);
 
 	return TRUE;
@@ -918,6 +949,23 @@ e_data_cal_respond_open (EDataCal *cal,
 
 	if (error != NULL)
 		g_error_free (error);
+
+	/* Dispatch any pending operations. */
+
+	g_mutex_lock (&cal->priv->open_lock);
+
+	if (opid == cal->priv->open_opid) {
+		OperationData *op;
+
+		cal->priv->open_opid = 0;
+
+		while (!g_queue_is_empty (&cal->priv->open_queue)) {
+			op = g_queue_pop_head (&cal->priv->open_queue);
+			e_operation_pool_push (ops_pool, op);
+		}
+	}
+
+	g_mutex_unlock (&cal->priv->open_lock);
 }
 
 /**
@@ -1668,6 +1716,11 @@ data_cal_finalize (GObject *object)
 		priv->dbus_interface = NULL;
 	}
 
+	g_mutex_clear (&priv->open_lock);
+
+	/* This should be empty now, else we leak memory. */
+	g_warn_if_fail (g_queue_is_empty (&priv->open_queue));
+
 	/* Chain up to parent's finalize() method. */
 	G_OBJECT_CLASS (e_data_cal_parent_class)->finalize (object);
 }
@@ -1761,6 +1814,8 @@ e_data_cal_init (EDataCal *ecal)
 		g_direct_hash, g_direct_equal, NULL, g_object_unref);
 	g_rec_mutex_init (&ecal->priv->pending_ops_lock);
 
+	g_mutex_init (&ecal->priv->open_lock);
+
 	dbus_interface = ecal->priv->dbus_interface;
 	g_signal_connect (
 		dbus_interface, "handle-open",



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]