[libshumate] file-cache: Make store_tile asynchronous
- From: Marcus Lundblad <mlundblad src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libshumate] file-cache: Make store_tile asynchronous
- Date: Fri, 2 Apr 2021 06:41:53 +0000 (UTC)
commit 957a56611cbaca9aec51d157ce5a437196a71be4
Author: James Westman <james jwestman net>
Date: Thu Mar 25 16:39:35 2021 -0500
file-cache: Make store_tile asynchronous
Previously it had the signature of an asynchronous method, but actually
did all its work synchronously.
shumate/shumate-file-cache.c | 202 +++++++++++++++++++++++++------------------
shumate/shumate-file-cache.h | 20 +++++
2 files changed, 137 insertions(+), 85 deletions(-)
---
diff --git a/shumate/shumate-file-cache.c b/shumate/shumate-file-cache.c
index 621205a..3f1615d 100644
--- a/shumate/shumate-file-cache.c
+++ b/shumate/shumate-file-cache.c
@@ -70,6 +70,11 @@ typedef struct
G_DEFINE_TYPE_WITH_PRIVATE (ShumateFileCache, shumate_file_cache, G_TYPE_OBJECT);
+
+typedef char sqlite_str;
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (sqlite_str, sqlite3_free);
+
+
static void finalize_sql (ShumateFileCache *file_cache);
static void init_cache (ShumateFileCache *file_cache);
static char *get_filename (ShumateFileCache *file_cache,
@@ -78,10 +83,6 @@ static void delete_tile (ShumateFileCache *file_cache,
const char *filename);
static gboolean create_cache_dir (const char *dir_name);
-static void store_tile (ShumateFileCache *self,
- ShumateTile *tile,
- const char *contents,
- gsize size);
static void on_tile_filled (ShumateFileCache *self,
ShumateTile *tile);
@@ -570,80 +571,6 @@ shumate_file_cache_mark_up_to_date (ShumateFileCache *self,
}
-static void
-store_tile (ShumateFileCache *self,
- ShumateTile *tile,
- const char *contents,
- gsize size)
-{
- ShumateFileCachePrivate *priv = shumate_file_cache_get_instance_private (self);
- char *query = NULL;
- char *error = NULL;
- char *path = NULL;
- char *filename = NULL;
- GError *gerror = NULL;
- GFile *file;
- GFileOutputStream *ostream;
- gsize bytes_written;
-
- DEBUG ("Update of %p", tile);
-
- filename = get_filename (self, tile);
- file = g_file_new_for_path (filename);
-
- /* If the file exists, delete it */
- g_file_delete (file, NULL, NULL);
-
- /* If needed, create the cache's dirs */
- path = g_path_get_dirname (filename);
- if (g_mkdir_with_parents (path, 0700) == -1)
- {
- if (errno != EEXIST)
- {
- g_warning ("Unable to create the image cache path '%s': %s",
- path, g_strerror (errno));
- goto store_next;
- }
- }
-
- ostream = g_file_create (file, G_FILE_CREATE_PRIVATE, NULL, &gerror);
- if (!ostream)
- {
- DEBUG ("GFileOutputStream creation failed: %s", gerror->message);
- g_error_free (gerror);
- goto store_next;
- }
-
- /* Write the cache */
- if (!g_output_stream_write_all (G_OUTPUT_STREAM (ostream), contents, size, &bytes_written, NULL, &gerror))
- {
- DEBUG ("Writing file contents failed: %s", gerror->message);
- g_error_free (gerror);
- g_object_unref (ostream);
- goto store_next;
- }
-
- g_object_unref (ostream);
-
- query = sqlite3_mprintf ("REPLACE INTO tiles (filename, etag, size) VALUES (%Q, %Q, %d)",
- filename,
- shumate_tile_get_etag (tile),
- size);
- sqlite3_exec (priv->db, query, NULL, NULL, &error);
- if (error != NULL)
- {
- DEBUG ("Saving Etag and size failed: %s", error);
- sqlite3_free (error);
- }
- sqlite3_free (query);
-
-store_next:
- g_free (filename);
- g_free (path);
- g_object_unref (file);
-}
-
-
static void
on_tile_filled (ShumateFileCache *self,
ShumateTile *tile)
@@ -939,6 +866,27 @@ shumate_file_cache_get_tile_finish (ShumateFileCache *self,
}
+typedef struct {
+ ShumateFileCache *self;
+ char *etag;
+ GBytes *bytes;
+ char *filename;
+} StoreTileData;
+
+static void
+store_tile_data_free (StoreTileData *data)
+{
+ g_clear_object (&data->self);
+ g_clear_pointer (&data->etag, g_free);
+ g_clear_pointer (&data->bytes, g_bytes_unref);
+ g_clear_pointer (&data->filename, g_free);
+ g_free (data);
+}
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (StoreTileData, store_tile_data_free);
+
+static void on_file_created (GObject *object, GAsyncResult *result, gpointer user_data);
+static void on_file_written (GObject *object, GAsyncResult *result, gpointer user_data);
+
/**
* shumate_file_cache_store_tile_async:
* @self: an #ShumateFileCache
@@ -961,8 +909,10 @@ shumate_file_cache_store_tile_async (ShumateFileCache *self,
gpointer user_data)
{
g_autoptr(GTask) task = NULL;
- gconstpointer contents;
- gsize size;
+ g_autofree char *filename = NULL;
+ g_autoptr(GFile) file = NULL;
+ g_autofree char *path = NULL;
+ StoreTileData *data;
g_return_if_fail (SHUMATE_IS_FILE_CACHE (self));
g_return_if_fail (SHUMATE_IS_TILE (tile));
@@ -972,13 +922,86 @@ shumate_file_cache_store_tile_async (ShumateFileCache *self,
task = g_task_new (self, cancellable, callback, user_data);
g_task_set_source_tag (task, shumate_file_cache_store_tile_async);
- if (etag != NULL)
- shumate_tile_set_etag (tile, etag);
+ filename = get_filename (self, tile);
+ file = g_file_new_for_path (filename);
- contents = g_bytes_get_data (bytes, &size);
+ DEBUG ("Update of %p", tile);
- // TODO: Make store_tile an async function
- store_tile (self, tile, contents, size);
+ /* If needed, create the cache's dirs */
+ path = g_path_get_dirname (filename);
+ if (g_mkdir_with_parents (path, 0700) == -1)
+ {
+ if (errno != EEXIST)
+ {
+ const char *error_string = g_strerror (errno);
+ g_task_return_new_error (task, SHUMATE_FILE_CACHE_ERROR,
+ SHUMATE_FILE_CACHE_ERROR_FAILED,
+ "Failed to create cache directory %s: %s", path, error_string);
+ return;
+ }
+ }
+
+ data = g_new0 (StoreTileData, 1);
+ data->self = g_object_ref (self);
+ data->etag = g_strdup (etag);
+ data->bytes = g_bytes_ref (bytes);
+ data->filename = g_steal_pointer (&filename);
+ g_task_set_task_data (task, data, (GDestroyNotify) store_tile_data_free);
+
+ g_file_create_async (file, G_FILE_CREATE_PRIVATE, G_PRIORITY_DEFAULT, cancellable, on_file_created,
g_object_ref (task));
+}
+
+static void
+on_file_created (GObject *object, GAsyncResult *res, gpointer user_data)
+{
+ g_autoptr(GTask) task = user_data;
+ StoreTileData *data = g_task_get_task_data (task);
+ GCancellable *cancellable = g_task_get_cancellable (task);
+ GError *error = NULL;
+ g_autoptr(GFileOutputStream) ostream = NULL;
+ gconstpointer contents;
+ gsize size;
+
+ ostream = g_file_create_finish (G_FILE (object), res, &error);
+ if (error != NULL)
+ {
+ g_task_return_error (task, error);
+ return;
+ }
+
+ contents = g_bytes_get_data (data->bytes, &size);
+
+ g_output_stream_write_all_async (G_OUTPUT_STREAM (ostream),
+ contents, size, G_PRIORITY_DEFAULT,
+ cancellable, on_file_written, g_object_ref (task));
+}
+
+static void
+on_file_written (GObject *object, GAsyncResult *res, gpointer user_data)
+{
+ g_autoptr(GTask) task = user_data;
+ StoreTileData *data = g_task_get_task_data (task);
+ ShumateFileCachePrivate *priv = shumate_file_cache_get_instance_private (data->self);
+ g_autoptr(sqlite_str) query = NULL;
+ g_autoptr(sqlite_str) sql_error = NULL;
+ GError *error = NULL;
+
+ g_output_stream_write_all_finish (G_OUTPUT_STREAM (object), res, NULL, &error);
+ if (error != NULL)
+ {
+ g_task_return_error (task, error);
+ return;
+ }
+
+ query = sqlite3_mprintf ("REPLACE INTO tiles (filename, etag, size) VALUES (%Q, %Q, %d)",
+ data->filename, data->etag, g_bytes_get_size (data->bytes));
+ sqlite3_exec (priv->db, query, NULL, NULL, &sql_error);
+ if (sql_error != NULL)
+ {
+ g_task_return_new_error (task, SHUMATE_FILE_CACHE_ERROR, SHUMATE_FILE_CACHE_ERROR_FAILED,
+ "Failed to insert tile into SQLite database: %s", sql_error);
+ return;
+ }
g_task_return_boolean (task, TRUE);
}
@@ -1005,3 +1028,12 @@ shumate_file_cache_store_tile_finish (ShumateFileCache *self,
return g_task_propagate_boolean (G_TASK (result), error);
}
+
+/**
+ * shumate_file_cache_error_quark:
+ *
+ * Gets the #ShumateFileCache error quark.
+ *
+ * Returns: a #GQuark
+ */
+G_DEFINE_QUARK (shumate-file-cache-error-quark, shumate_file_cache_error);
diff --git a/shumate/shumate-file-cache.h b/shumate/shumate-file-cache.h
index cab63b1..8c382f5 100644
--- a/shumate/shumate-file-cache.h
+++ b/shumate/shumate-file-cache.h
@@ -30,6 +30,26 @@
G_BEGIN_DECLS
+/**
+ * SHUMATE_FILE_CACHE_ERROR:
+ *
+ * Error domain for errors that may occur while storing or retrieving tiles
+ * from a #ShumateFileCache. Errors in this domain will be from the
+ * #ShumateFileCacheError enum.
+ */
+#define SHUMATE_FILE_CACHE_ERROR shumate_file_cache_error_quark ()
+GQuark shumate_file_cache_error_quark (void);
+
+/**
+ * ShumateFileCacheError:
+ * @SHUMATE_FILE_CACHE_ERROR_FAILED: An unspecified error occurred during the operation.
+ *
+ * Error codes in the #SHUMATE_FILE_CACHE_ERROR domain.
+ */
+typedef enum {
+ SHUMATE_FILE_CACHE_ERROR_FAILED,
+} ShumateFileCacheError;
+
#define SHUMATE_TYPE_FILE_CACHE shumate_file_cache_get_type ()
G_DECLARE_DERIVABLE_TYPE (ShumateFileCache, shumate_file_cache, SHUMATE, FILE_CACHE, GObject)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]