diff pui-backend.c @ 31:9905d4ae351c

Fix continuos loop of update checks if the refresh cache interval is 0 If the interval for refreshing the cache is set to 0 each check for available updates refreshes the cache and causes an "updates-changed" signal to be emitted after a short delay which in turn triggers another check for updates. The "updates-changed" signal does not actually mean that the number of available updates has changed but rather that the package metadata cache has been invalidated. Fix this by blocking the "updates-changed" signal handler from when a periodic or irregular check is started until 4 seconds after it has finished. This is necessary since the signal will be delivered with a delay after a transaction has been completed. In addition prevent checks for updates triggered by the "updates-changed" signal from refreshing the cache even the interval is 0 since the emission of the signal implies that the cache has just been refreshed.
author Guido Berhoerster <guido+pui@berhoerster.name>
date Thu, 29 Aug 2019 13:48:47 +0200
parents adba37525ee5
children b9c65915cc54
line wrap: on
line diff
--- a/pui-backend.c	Wed Aug 28 13:29:23 2019 +0200
+++ b/pui-backend.c	Thu Aug 29 13:48:47 2019 +0200
@@ -36,7 +36,8 @@
 #include "pui-get-updates.h"
 #include "pui-types.h"
 
-#define	LOW_BATTERY_THRESHOLD	10.0
+#define	LOW_BATTERY_THRESHOLD		10.0	/* % */
+#define	UPDATES_CHANGED_UNBLOCK_DELAY	4	/* s */
 
 struct _PuiBackend {
 	GObject		parent_instance;
@@ -56,7 +57,8 @@
 	PkNetworkEnum	network_state;
 	gboolean	inhibited;
 	gboolean	is_battery_low;
-	guint		periodic_check_id;
+	guint		check_id;
+	guint		unblock_updates_changed_id;
 	guint		refresh_interval;
 	gboolean	use_mobile_connection;
 	guint		important_updates;
@@ -90,6 +92,7 @@
 static GParamSpec *properties[PROP_LAST] = { NULL };
 
 static gboolean	periodic_check(gpointer);
+static void	on_updates_changed(PkControl *, gpointer);
 
 GQuark
 pui_backend_error_quark(void)
@@ -120,6 +123,18 @@
 	}
 }
 
+static gboolean
+unblock_updates_changed(gpointer user_data)
+{
+	PuiBackend	*self = user_data;
+
+	g_signal_handlers_unblock_by_func(self->pk_control, on_updates_changed,
+	    self);
+	self->unblock_updates_changed_id = 0;
+
+	return (G_SOURCE_REMOVE);
+}
+
 static void
 on_get_updates_finished(GObject *source_object, GAsyncResult *async_result,
     gpointer user_data)
@@ -172,16 +187,55 @@
 
 	/* reschedule periodic check */
 	if (!self->inhibited) {
-		self->periodic_check_id =
+		self->check_id =
 		    g_timeout_add_seconds(PUI_CHECK_UPDATES_INTERVAL,
 		    periodic_check, self);
 	}
 
+	/* handle get-updates signals again after a short delay */
+	self->unblock_updates_changed_id =
+	    g_timeout_add_seconds(UPDATES_CHANGED_UNBLOCK_DELAY,
+	    unblock_updates_changed, self);
+
 	if (package_list != NULL) {
 		g_ptr_array_unref(package_list);
 	}
 }
 
+static void
+run_check(PuiBackend *self, gboolean refresh_cache)
+{
+	/* block any get-updates signals emitted when refreshing the cache */
+	if (self->unblock_updates_changed_id != 0) {
+		/* still blocked */
+		g_source_remove(self->unblock_updates_changed_id);
+		self->unblock_updates_changed_id = 0;
+	} else {
+		g_signal_handlers_block_by_func(self->pk_control,
+		    G_CALLBACK(on_updates_changed), self);
+	}
+
+	self->cancellable = g_cancellable_new();
+	pui_get_updates_async(self->pk_control,
+	    refresh_cache ? self->refresh_interval : G_MAXUINT,
+	    self->cancellable, on_get_updates_finished, self);
+
+	/* next periodic check will be scheduled after completion */
+	self->check_id = 0;
+}
+
+static gboolean
+irregular_check(gpointer user_data)
+{
+	PuiBackend	*self = user_data;
+
+	g_debug("running check");
+
+	run_check(self, FALSE);
+
+	return (G_SOURCE_REMOVE);
+}
+
 static gboolean
 periodic_check(gpointer user_data)
 {
@@ -189,12 +243,7 @@
 
 	g_debug("running periodic check");
 
-	self->cancellable = g_cancellable_new();
-	pui_get_updates_async(self->pk_control, self->refresh_interval,
-	    self->cancellable, on_get_updates_finished, self);
-
-	/* next periodic check will be scheduled after completion */
-	self->periodic_check_id = 0;
+	run_check(self, TRUE);
 
 	return (G_SOURCE_REMOVE);
 }
@@ -217,8 +266,8 @@
 	self->inhibited = inhibited;
 	if (inhibited) {
 		/* cancel periodic checks */
-		if (self->periodic_check_id != 0) {
-			g_source_remove(self->periodic_check_id);
+		if (self->check_id != 0) {
+			g_source_remove(self->check_id);
 		}
 
 		/* cancel running operation */
@@ -239,7 +288,7 @@
 		remaining_time = (elapsed_time < PUI_CHECK_UPDATES_INTERVAL) ?
 		    PUI_CHECK_UPDATES_INTERVAL - elapsed_time :
 		    PUI_STARTUP_DELAY;
-		self->periodic_check_id = g_timeout_add_seconds(remaining_time,
+		self->check_id = g_timeout_add_seconds(remaining_time,
 		    periodic_check, self);
 	}
 }
@@ -301,9 +350,14 @@
 {
 	PuiBackend	*self = PUI_BACKEND(object);
 
-	if (self->periodic_check_id != 0) {
-		g_source_remove(self->periodic_check_id);
-		self->periodic_check_id = 0;
+	if (self->check_id != 0) {
+		g_source_remove(self->check_id);
+		self->check_id = 0;
+	}
+
+	if (self->unblock_updates_changed_id != 0) {
+		g_source_remove(self->unblock_updates_changed_id);
+		self->unblock_updates_changed_id = 0;
 	}
 
 	if (self->transaction_list != NULL) {
@@ -493,19 +547,18 @@
 {
 	PuiBackend	*self = user_data;
 
-	g_debug("number of updates changed");
+	g_debug("package metatdata cache invalidated");
 
 	/*
 	 * schedule a check after a short delay so that a rapid succession of
 	 * signals is coalesced
 	 */
 	if (!self->inhibited) {
-		if (self->periodic_check_id != 0) {
-			g_source_remove(self->periodic_check_id);
+		if (self->check_id != 0) {
+			g_source_remove(self->check_id);
 		}
-		self->periodic_check_id =
-		    g_timeout_add_seconds(PUI_STARTUP_DELAY, periodic_check,
-		    self);
+		self->check_id = g_timeout_add_seconds(PUI_STARTUP_DELAY,
+		    irregular_check, self);
 	}
 }
 
@@ -639,7 +692,7 @@
 	/* get notification when the network state changes */
 	g_signal_connect(self->pk_control, "notify::network-state",
 	    G_CALLBACK(on_notify_network_state), self);
-	/* get notifications when the available package updates change */
+	/* get notifications when the package metatdata cache is invalidated */
 	g_signal_connect(self->pk_control, "updates-changed",
 	    G_CALLBACK(on_updates_changed), self);
 	/* get notifications when an application restart is required */