Mercurial > projects > package-update-indicator
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); |