comparison 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
comparison
equal deleted inserted replaced
30:811df672633d 31:9905d4ae351c
34 #include "pui-common.h" 34 #include "pui-common.h"
35 #include "pui-backend.h" 35 #include "pui-backend.h"
36 #include "pui-get-updates.h" 36 #include "pui-get-updates.h"
37 #include "pui-types.h" 37 #include "pui-types.h"
38 38
39 #define LOW_BATTERY_THRESHOLD 10.0 39 #define LOW_BATTERY_THRESHOLD 10.0 /* % */
40 #define UPDATES_CHANGED_UNBLOCK_DELAY 4 /* s */
40 41
41 struct _PuiBackend { 42 struct _PuiBackend {
42 GObject parent_instance; 43 GObject parent_instance;
43 PkControl *pk_control; 44 PkControl *pk_control;
44 GCancellable *cancellable; 45 GCancellable *cancellable;
54 gchar *pac; 55 gchar *pac;
55 gint64 last_check; 56 gint64 last_check;
56 PkNetworkEnum network_state; 57 PkNetworkEnum network_state;
57 gboolean inhibited; 58 gboolean inhibited;
58 gboolean is_battery_low; 59 gboolean is_battery_low;
59 guint periodic_check_id; 60 guint check_id;
61 guint unblock_updates_changed_id;
60 guint refresh_interval; 62 guint refresh_interval;
61 gboolean use_mobile_connection; 63 gboolean use_mobile_connection;
62 guint important_updates; 64 guint important_updates;
63 guint normal_updates; 65 guint normal_updates;
64 PuiRestart restart_type; 66 PuiRestart restart_type;
88 90
89 static guint signals[SIGNAL_LAST] = { 0 }; 91 static guint signals[SIGNAL_LAST] = { 0 };
90 static GParamSpec *properties[PROP_LAST] = { NULL }; 92 static GParamSpec *properties[PROP_LAST] = { NULL };
91 93
92 static gboolean periodic_check(gpointer); 94 static gboolean periodic_check(gpointer);
95 static void on_updates_changed(PkControl *, gpointer);
93 96
94 GQuark 97 GQuark
95 pui_backend_error_quark(void) 98 pui_backend_error_quark(void)
96 { 99 {
97 return (g_quark_from_static_string("pui-backend-error-quark")); 100 return (g_quark_from_static_string("pui-backend-error-quark"));
116 self->important_updates++; 119 self->important_updates++;
117 break; 120 break;
118 default: 121 default:
119 break; 122 break;
120 } 123 }
124 }
125
126 static gboolean
127 unblock_updates_changed(gpointer user_data)
128 {
129 PuiBackend *self = user_data;
130
131 g_signal_handlers_unblock_by_func(self->pk_control, on_updates_changed,
132 self);
133 self->unblock_updates_changed_id = 0;
134
135 return (G_SOURCE_REMOVE);
121 } 136 }
122 137
123 static void 138 static void
124 on_get_updates_finished(GObject *source_object, GAsyncResult *async_result, 139 on_get_updates_finished(GObject *source_object, GAsyncResult *async_result,
125 gpointer user_data) 140 gpointer user_data)
170 out: 185 out:
171 g_clear_object(&self->cancellable); 186 g_clear_object(&self->cancellable);
172 187
173 /* reschedule periodic check */ 188 /* reschedule periodic check */
174 if (!self->inhibited) { 189 if (!self->inhibited) {
175 self->periodic_check_id = 190 self->check_id =
176 g_timeout_add_seconds(PUI_CHECK_UPDATES_INTERVAL, 191 g_timeout_add_seconds(PUI_CHECK_UPDATES_INTERVAL,
177 periodic_check, self); 192 periodic_check, self);
178 } 193 }
179 194
195 /* handle get-updates signals again after a short delay */
196 self->unblock_updates_changed_id =
197 g_timeout_add_seconds(UPDATES_CHANGED_UNBLOCK_DELAY,
198 unblock_updates_changed, self);
199
180 if (package_list != NULL) { 200 if (package_list != NULL) {
181 g_ptr_array_unref(package_list); 201 g_ptr_array_unref(package_list);
182 } 202 }
183 } 203 }
184 204
205 static void
206 run_check(PuiBackend *self, gboolean refresh_cache)
207 {
208 /* block any get-updates signals emitted when refreshing the cache */
209 if (self->unblock_updates_changed_id != 0) {
210 /* still blocked */
211 g_source_remove(self->unblock_updates_changed_id);
212 self->unblock_updates_changed_id = 0;
213 } else {
214 g_signal_handlers_block_by_func(self->pk_control,
215 G_CALLBACK(on_updates_changed), self);
216 }
217
218 self->cancellable = g_cancellable_new();
219 pui_get_updates_async(self->pk_control,
220 refresh_cache ? self->refresh_interval : G_MAXUINT,
221 self->cancellable, on_get_updates_finished, self);
222
223 /* next periodic check will be scheduled after completion */
224 self->check_id = 0;
225 }
226
227 static gboolean
228 irregular_check(gpointer user_data)
229 {
230 PuiBackend *self = user_data;
231
232 g_debug("running check");
233
234 run_check(self, FALSE);
235
236 return (G_SOURCE_REMOVE);
237 }
238
185 static gboolean 239 static gboolean
186 periodic_check(gpointer user_data) 240 periodic_check(gpointer user_data)
187 { 241 {
188 PuiBackend *self = user_data; 242 PuiBackend *self = user_data;
189 243
190 g_debug("running periodic check"); 244 g_debug("running periodic check");
191 245
192 self->cancellable = g_cancellable_new(); 246 run_check(self, TRUE);
193 pui_get_updates_async(self->pk_control, self->refresh_interval,
194 self->cancellable, on_get_updates_finished, self);
195
196 /* next periodic check will be scheduled after completion */
197 self->periodic_check_id = 0;
198 247
199 return (G_SOURCE_REMOVE); 248 return (G_SOURCE_REMOVE);
200 } 249 }
201 250
202 static void 251 static void
215 } 264 }
216 265
217 self->inhibited = inhibited; 266 self->inhibited = inhibited;
218 if (inhibited) { 267 if (inhibited) {
219 /* cancel periodic checks */ 268 /* cancel periodic checks */
220 if (self->periodic_check_id != 0) { 269 if (self->check_id != 0) {
221 g_source_remove(self->periodic_check_id); 270 g_source_remove(self->check_id);
222 } 271 }
223 272
224 /* cancel running operation */ 273 /* cancel running operation */
225 if ((self->cancellable != NULL) && 274 if ((self->cancellable != NULL) &&
226 !g_cancellable_is_cancelled(self->cancellable)) { 275 !g_cancellable_is_cancelled(self->cancellable)) {
237 * wait until the interval has passed 286 * wait until the interval has passed
238 */ 287 */
239 remaining_time = (elapsed_time < PUI_CHECK_UPDATES_INTERVAL) ? 288 remaining_time = (elapsed_time < PUI_CHECK_UPDATES_INTERVAL) ?
240 PUI_CHECK_UPDATES_INTERVAL - elapsed_time : 289 PUI_CHECK_UPDATES_INTERVAL - elapsed_time :
241 PUI_STARTUP_DELAY; 290 PUI_STARTUP_DELAY;
242 self->periodic_check_id = g_timeout_add_seconds(remaining_time, 291 self->check_id = g_timeout_add_seconds(remaining_time,
243 periodic_check, self); 292 periodic_check, self);
244 } 293 }
245 } 294 }
246 295
247 static void 296 static void
299 static void 348 static void
300 pui_backend_dispose(GObject *object) 349 pui_backend_dispose(GObject *object)
301 { 350 {
302 PuiBackend *self = PUI_BACKEND(object); 351 PuiBackend *self = PUI_BACKEND(object);
303 352
304 if (self->periodic_check_id != 0) { 353 if (self->check_id != 0) {
305 g_source_remove(self->periodic_check_id); 354 g_source_remove(self->check_id);
306 self->periodic_check_id = 0; 355 self->check_id = 0;
356 }
357
358 if (self->unblock_updates_changed_id != 0) {
359 g_source_remove(self->unblock_updates_changed_id);
360 self->unblock_updates_changed_id = 0;
307 } 361 }
308 362
309 if (self->transaction_list != NULL) { 363 if (self->transaction_list != NULL) {
310 g_clear_object(&self->transaction_list); 364 g_clear_object(&self->transaction_list);
311 } 365 }
491 static void 545 static void
492 on_updates_changed(PkControl *control, gpointer user_data) 546 on_updates_changed(PkControl *control, gpointer user_data)
493 { 547 {
494 PuiBackend *self = user_data; 548 PuiBackend *self = user_data;
495 549
496 g_debug("number of updates changed"); 550 g_debug("package metatdata cache invalidated");
497 551
498 /* 552 /*
499 * schedule a check after a short delay so that a rapid succession of 553 * schedule a check after a short delay so that a rapid succession of
500 * signals is coalesced 554 * signals is coalesced
501 */ 555 */
502 if (!self->inhibited) { 556 if (!self->inhibited) {
503 if (self->periodic_check_id != 0) { 557 if (self->check_id != 0) {
504 g_source_remove(self->periodic_check_id); 558 g_source_remove(self->check_id);
505 } 559 }
506 self->periodic_check_id = 560 self->check_id = g_timeout_add_seconds(PUI_STARTUP_DELAY,
507 g_timeout_add_seconds(PUI_STARTUP_DELAY, periodic_check, 561 irregular_check, self);
508 self);
509 } 562 }
510 } 563 }
511 564
512 static void 565 static void
513 on_restart_schedule(PkControl *control, gpointer user_data) 566 on_restart_schedule(PkControl *control, gpointer user_data)
637 } 690 }
638 691
639 /* get notification when the network state changes */ 692 /* get notification when the network state changes */
640 g_signal_connect(self->pk_control, "notify::network-state", 693 g_signal_connect(self->pk_control, "notify::network-state",
641 G_CALLBACK(on_notify_network_state), self); 694 G_CALLBACK(on_notify_network_state), self);
642 /* get notifications when the available package updates change */ 695 /* get notifications when the package metatdata cache is invalidated */
643 g_signal_connect(self->pk_control, "updates-changed", 696 g_signal_connect(self->pk_control, "updates-changed",
644 G_CALLBACK(on_updates_changed), self); 697 G_CALLBACK(on_updates_changed), self);
645 /* get notifications when an application restart is required */ 698 /* get notifications when an application restart is required */
646 g_signal_connect(self->pk_control, "restart-schedule", 699 g_signal_connect(self->pk_control, "restart-schedule",
647 G_CALLBACK(on_restart_schedule), self); 700 G_CALLBACK(on_restart_schedule), self);