Commit e098781b authored by Cosimo Cecchi's avatar Cosimo Cecchi

bookmark-list: make sure to avoid sync I/O while loading/saving

Last patch introduces sync I/O in the load and save paths; avoid that by
explicitly using separate threads for saving and loading, thanks to
g_simple_async_result_run_in_thread().
parent ed905771
......@@ -462,82 +462,142 @@ nautilus_bookmark_list_length (NautilusBookmarkList *bookmarks)
}
static void
load_file_finish (NautilusBookmarkList *bookmarks,
GObject *source,
GAsyncResult *res)
process_next_op (NautilusBookmarkList *bookmarks);
static void
op_processed_cb (NautilusBookmarkList *self)
{
GError *error = NULL;
gchar *contents = NULL;
g_file_load_contents_finish (G_FILE (source),
res, &contents, NULL, NULL, &error);
if (error == NULL) {
char **lines;
int i;
lines = g_strsplit (contents, "\n", -1);
for (i = 0; lines[i]; i++) {
/* Ignore empty or invalid lines that cannot be parsed properly */
if (lines[i][0] != '\0' && lines[i][0] != ' ') {
/* gtk 2.7/2.8 might have labels appended to bookmarks which are separated by a space */
/* we must seperate the bookmark uri and the potential label */
char *space, *label;
label = NULL;
space = strchr (lines[i], ' ');
if (space) {
*space = '\0';
label = g_strdup (space + 1);
}
insert_bookmark_internal (bookmarks,
new_bookmark_from_uri (lines[i], label),
-1);
g_free (label);
g_queue_pop_tail (self->pending_ops);
if (!g_queue_is_empty (self->pending_ops)) {
process_next_op (self);
}
}
static void
load_callback (GObject *source,
GAsyncResult *res,
gpointer user_data)
{
NautilusBookmarkList *self = NAUTILUS_BOOKMARK_LIST (source);
gchar *contents;
char **lines;
int i;
contents = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res));
if (contents == NULL) {
return;
}
lines = g_strsplit (contents, "\n", -1);
for (i = 0; lines[i]; i++) {
/* Ignore empty or invalid lines that cannot be parsed properly */
if (lines[i][0] != '\0' && lines[i][0] != ' ') {
/* gtk 2.7/2.8 might have labels appended to bookmarks which are separated by a space */
/* we must seperate the bookmark uri and the potential label */
char *space, *label;
label = NULL;
space = strchr (lines[i], ' ');
if (space) {
*space = '\0';
label = g_strdup (space + 1);
}
}
g_free (contents);
g_strfreev (lines);
g_signal_emit (bookmarks, signals[CHANGED], 0);
} else if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) {
g_warning ("Could not load bookmark file: %s\n", error->message);
g_error_free (error);
insert_bookmark_internal (self, new_bookmark_from_uri (lines[i], label), -1);
g_free (label);
}
}
g_signal_emit (self, signals[CHANGED], 0);
op_processed_cb (self);
g_strfreev (lines);
}
static void
load_file_async (NautilusBookmarkList *self,
GAsyncReadyCallback callback)
load_io_thread (GSimpleAsyncResult *result,
GObject *object,
GCancellable *cancellable)
{
GFile *file;
gchar *contents;
GError *error = NULL;
file = nautilus_bookmark_list_get_file ();
if (!g_file_query_exists (file, NULL)) {
file = nautilus_bookmark_list_get_legacy_file ();
}
g_file_load_contents (file, NULL, &contents, NULL, NULL, &error);
if (error != NULL) {
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) {
g_warning ("Could not load bookmark file: %s\n", error->message);
}
g_error_free (error);
} else {
g_simple_async_result_set_op_res_gpointer (result, contents, g_free);
}
}
static void
load_file_async (NautilusBookmarkList *self)
{
GSimpleAsyncResult *result;
/* Wipe out old list. */
clear (self);
/* keep the bookmark list alive */
g_object_ref (self);
g_file_load_contents_async (file, NULL, callback, self);
result = g_simple_async_result_new (G_OBJECT (self),
load_callback, NULL, NULL);
g_simple_async_result_run_in_thread (result, load_io_thread,
G_PRIORITY_DEFAULT, NULL);
g_object_unref (result);
}
static void
save_callback (GObject *source,
GAsyncResult *res,
gpointer user_data)
{
NautilusBookmarkList *self = NAUTILUS_BOOKMARK_LIST (source);
GFile *file;
/* re-enable bookmark file monitoring */
file = nautilus_bookmark_list_get_file ();
self->monitor = g_file_monitor_file (file, 0, NULL, NULL);
g_object_unref (file);
g_file_monitor_set_rate_limit (self->monitor, 1000);
g_signal_connect (self->monitor, "changed",
G_CALLBACK (bookmark_monitor_changed_cb), self);
op_processed_cb (self);
}
static void
save_file_finish (NautilusBookmarkList *bookmarks,
GObject *source,
GAsyncResult *res)
save_io_thread (GSimpleAsyncResult *result,
GObject *object,
GCancellable *cancellable)
{
gchar *contents, *path;
GFile *parent, *file;
GError *error = NULL;
GFile *file;
g_file_replace_contents_finish (G_FILE (source),
res, NULL, &error);
file = nautilus_bookmark_list_get_file ();
parent = g_file_get_parent (file);
path = g_file_get_path (parent);
g_mkdir_with_parents (path, 0700);
g_free (path);
g_object_unref (parent);
contents = g_simple_async_result_get_op_res_gpointer (result);
g_file_replace_contents (file,
contents, strlen (contents),
NULL, FALSE, 0, NULL,
NULL, &error);
if (error != NULL) {
g_warning ("Unable to replace contents of the bookmarks file: %s",
......@@ -545,37 +605,26 @@ save_file_finish (NautilusBookmarkList *bookmarks,
g_error_free (error);
}
file = nautilus_bookmark_list_get_file ();
/* re-enable bookmark file monitoring */
bookmarks->monitor = g_file_monitor_file (file, 0, NULL, NULL);
g_file_monitor_set_rate_limit (bookmarks->monitor, 1000);
g_signal_connect (bookmarks->monitor, "changed",
G_CALLBACK (bookmark_monitor_changed_cb), bookmarks);
g_object_unref (file);
}
static void
save_file_async (NautilusBookmarkList *bookmarks,
GAsyncReadyCallback callback)
save_file_async (NautilusBookmarkList *self)
{
GFile *file;
GList *l;
GSimpleAsyncResult *result;
GString *bookmark_string;
GFile *parent;
char *path;
gchar *contents;
GList *l;
bookmark_string = g_string_new (NULL);
/* temporarily disable bookmark file monitoring when writing file */
if (bookmarks->monitor != NULL) {
g_file_monitor_cancel (bookmarks->monitor);
bookmarks->monitor = NULL;
if (self->monitor != NULL) {
g_file_monitor_cancel (self->monitor);
self->monitor = NULL;
}
file = nautilus_bookmark_list_get_file ();
bookmark_string = g_string_new (NULL);
for (l = bookmarks->list; l; l = l->next) {
for (l = self->list; l; l = l->next) {
NautilusBookmark *bookmark;
bookmark = NAUTILUS_BOOKMARK (l->data);
......@@ -597,48 +646,14 @@ save_file_async (NautilusBookmarkList *bookmarks,
}
}
/* keep the bookmark list alive */
g_object_ref (bookmarks);
parent = g_file_get_parent (file);
path = g_file_get_path (parent);
g_mkdir_with_parents (path, 0700);
g_free (path);
g_object_unref (parent);
g_file_replace_contents_async (file, bookmark_string->str,
bookmark_string->len, NULL,
FALSE, 0, NULL, callback,
bookmarks);
g_object_unref (file);
}
static void
process_next_op (NautilusBookmarkList *bookmarks);
static void
op_processed_cb (GObject *source,
GAsyncResult *res,
gpointer user_data)
{
NautilusBookmarkList *self = user_data;
int op;
op = GPOINTER_TO_INT (g_queue_pop_tail (self->pending_ops));
if (op == LOAD_JOB) {
load_file_finish (self, source, res);
} else {
save_file_finish (self, source, res);
}
if (!g_queue_is_empty (self->pending_ops)) {
process_next_op (self);
}
result = g_simple_async_result_new (G_OBJECT (self),
save_callback, NULL, NULL);
contents = g_string_free (bookmark_string, FALSE);
g_simple_async_result_set_op_res_gpointer (result, contents, g_free);
/* release the reference acquired during the _async method */
g_object_unref (self);
g_simple_async_result_run_in_thread (result, save_io_thread,
G_PRIORITY_DEFAULT, NULL);
g_object_unref (result);
}
static void
......@@ -649,9 +664,9 @@ process_next_op (NautilusBookmarkList *bookmarks)
op = GPOINTER_TO_INT (g_queue_peek_tail (bookmarks->pending_ops));
if (op == LOAD_JOB) {
load_file_async (bookmarks, op_processed_cb);
load_file_async (bookmarks);
} else {
save_file_async (bookmarks, op_processed_cb);
save_file_async (bookmarks);
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment