[gom] gom: Add support for batched writes
- From: Bastien Nocera <hadess src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gom] gom: Add support for batched writes
- Date: Tue, 4 Nov 2014 18:56:39 +0000 (UTC)
commit 0faa9577dc961a416ef16b884c22a88f3c82345a
Author: Bastien Nocera <hadess hadess net>
Date: Sun Sep 21 18:55:39 2014 +0200
gom: Add support for batched writes
https://bugzilla.gnome.org/show_bug.cgi?id=730950
gom/gom-resource-group.c | 224 ++++++++++++++++++++++++++++++++++++++++++++++
gom/gom-resource-group.h | 13 +++
2 files changed, 237 insertions(+), 0 deletions(-)
---
diff --git a/gom/gom-resource-group.c b/gom/gom-resource-group.c
index c293540..8ee9ab5 100644
--- a/gom/gom-resource-group.c
+++ b/gom/gom-resource-group.c
@@ -33,12 +33,18 @@ G_DEFINE_TYPE(GomResourceGroup, gom_resource_group, G_TYPE_OBJECT)
struct _GomResourceGroupPrivate
{
GomRepository *repository;
+
+ /* Read group */
guint count;
GomFilter *filter;
GType resource_type;
GHashTable *items;
gchar *m2m_table;
GType m2m_type;
+
+ /* Write group */
+ gboolean is_writable;
+ GPtrArray *to_write;
};
enum
@@ -50,11 +56,206 @@ enum
PROP_M2M_TYPE,
PROP_RESOURCE_TYPE,
PROP_REPOSITORY,
+ PROP_IS_WRITABLE,
LAST_PROP
};
static GParamSpec *gParamSpecs[LAST_PROP];
+GomResourceGroup *
+gom_resource_group_new (GomRepository *repository)
+{
+ GomResourceGroup *group;
+
+ group = g_object_new(GOM_TYPE_RESOURCE_GROUP,
+ "repository", repository,
+ "is-writable", TRUE,
+ NULL);
+ return group;
+}
+
+gboolean
+gom_resource_group_append (GomResourceGroup *group,
+ GomResource *resource)
+{
+ g_return_val_if_fail(GOM_IS_RESOURCE_GROUP(group), FALSE);
+ g_return_val_if_fail(GOM_IS_RESOURCE(resource), FALSE);
+
+ if (!group->priv->to_write)
+ group->priv->to_write = g_ptr_array_new_with_free_func(g_object_unref);
+ g_ptr_array_add (group->priv->to_write, g_object_ref(resource));
+
+ return TRUE;
+}
+
+#define EXECUTE_OR_GOTO(adaper, sql, error, label) \
+ G_STMT_START { \
+ GomCommand *c = g_object_new(GOM_TYPE_COMMAND, \
+ "adapter", adapter, \
+ "sql", sql, \
+ NULL); \
+ if (!gom_command_execute(c, NULL, error)) { \
+ g_object_unref(c); \
+ goto label; \
+ } \
+ g_object_unref(c); \
+ } G_STMT_END
+
+static void
+gom_resource_group_write_cb (GomAdapter *adapter,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple = user_data;
+ GomResourceGroup *group;
+ GError *error = NULL;
+ GAsyncQueue *queue;
+ guint i;
+ gboolean got_error;
+ GPtrArray *items;
+
+ g_return_if_fail(GOM_IS_ADAPTER(adapter));
+ g_return_if_fail(G_IS_SIMPLE_ASYNC_RESULT(simple));
+
+ group = GOM_RESOURCE_GROUP(g_async_result_get_source_object(G_ASYNC_RESULT(simple)));
+
+ g_assert(GOM_IS_ADAPTER(adapter));
+
+ items = g_object_get_data(G_OBJECT(simple), "items");
+ g_ptr_array_set_free_func(items, NULL);
+ queue = g_object_get_data(G_OBJECT(simple), "queue");
+
+ /* do BEGIN */
+ EXECUTE_OR_GOTO(adapter, "BEGIN;", &error, rollback);
+
+ got_error = FALSE;
+
+ for (i = 0; i < items->len; i++) {
+ GomResource *item;
+
+ item = g_ptr_array_index(items, i);
+ if (got_error ||
+ !gom_resource_do_save (item, adapter, &error)) {
+ got_error = TRUE;
+ }
+ g_object_unref(item);
+ }
+
+ if (got_error)
+ goto rollback;
+
+ EXECUTE_OR_GOTO(adapter, "COMMIT;", &error, rollback);
+
+ g_simple_async_result_set_op_res_gboolean(simple, TRUE);
+ goto out;
+
+rollback:
+ EXECUTE_OR_GOTO(adapter, "ROLLBACK;", NULL, error);
+
+error:
+ g_assert(error);
+ g_simple_async_result_take_error(simple, error);
+
+out:
+ g_ptr_array_unref(items);
+ g_object_unref(group);
+ if (!queue)
+ g_simple_async_result_complete_in_idle(simple);
+ else
+ g_async_queue_push(queue, GINT_TO_POINTER(TRUE));
+}
+
+gboolean
+gom_resource_group_write_sync (GomResourceGroup *group,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+ gboolean ret;
+ GAsyncQueue *queue;
+ GomAdapter *adapter;
+ guint i;
+
+ g_return_val_if_fail(GOM_IS_RESOURCE_GROUP(group), FALSE);
+ g_return_val_if_fail(group->priv->is_writable, FALSE);
+
+ queue = g_async_queue_new();
+
+ simple = g_simple_async_result_new(G_OBJECT(group), NULL, NULL,
+ gom_resource_group_write_sync);
+ if (!group->priv->to_write)
+ return TRUE;
+ adapter = gom_repository_get_adapter(group->priv->repository);
+
+ g_object_set_data(G_OBJECT(simple), "queue", queue);
+ for (i = 0; i < group->priv->to_write->len; i++)
+ gom_resource_build_save_cmd(g_ptr_array_index(group->priv->to_write, i) , adapter);
+ g_object_set_data(G_OBJECT(simple), "items", group->priv->to_write);
+ group->priv->to_write = NULL;
+
+ gom_adapter_queue_write(adapter, gom_resource_group_write_cb, simple);
+ g_async_queue_pop(queue);
+ g_async_queue_unref(queue);
+
+ if (!(ret = g_simple_async_result_get_op_res_gboolean(simple))) {
+ g_simple_async_result_propagate_error(simple, error);
+ }
+ g_object_unref(simple);
+
+ return ret;
+}
+
+void
+gom_resource_group_write_async (GomResourceGroup *group,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GomResourceGroupPrivate *priv;
+ GSimpleAsyncResult *simple;
+ GomAdapter *adapter;
+ guint i;
+
+ g_return_if_fail(GOM_IS_RESOURCE_GROUP(group));
+ g_return_if_fail(callback != NULL);
+ g_return_if_fail(group->priv->is_writable);
+
+ priv = group->priv;
+
+ simple = g_simple_async_result_new(G_OBJECT(group), callback, user_data,
+ gom_resource_group_write_async);
+ if (!group->priv->to_write) {
+ g_simple_async_result_set_op_res_gboolean(simple, TRUE);
+ g_simple_async_result_complete_in_idle(simple);
+ return;
+ }
+ adapter = gom_repository_get_adapter(priv->repository);
+
+ for (i = 0; i < group->priv->to_write->len; i++)
+ gom_resource_build_save_cmd(g_ptr_array_index(group->priv->to_write, i) , adapter);
+ g_object_set_data(G_OBJECT(simple), "items", group->priv->to_write);
+ group->priv->to_write = NULL;
+
+ gom_adapter_queue_read(adapter, gom_resource_group_write_cb, simple);
+}
+
+gboolean
+gom_resource_group_write_finish (GomResourceGroup *group,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple = (GSimpleAsyncResult *)result;
+ gboolean ret;
+
+ g_return_val_if_fail(GOM_IS_RESOURCE_GROUP(group), FALSE);
+ g_return_val_if_fail(G_IS_SIMPLE_ASYNC_RESULT(simple), FALSE);
+ g_return_val_if_fail(group->priv->is_writable, FALSE);
+
+ if (!(ret = g_simple_async_result_get_op_res_gboolean(simple))) {
+ g_simple_async_result_propagate_error(simple, error);
+ }
+ g_object_unref(simple);
+
+ return ret;
+}
+
static GomFilter *
gom_resource_group_get_filter (GomResourceGroup *group)
{
@@ -79,6 +280,7 @@ guint
gom_resource_group_get_count (GomResourceGroup *group)
{
g_return_val_if_fail(GOM_IS_RESOURCE_GROUP(group), 0);
+ g_return_val_if_fail(!group->priv->is_writable, 0);
return group->priv->count;
}
@@ -96,6 +298,7 @@ const gchar *
gom_resource_group_get_m2m_table (GomResourceGroup *group)
{
g_return_val_if_fail(GOM_IS_RESOURCE_GROUP(group), NULL);
+ g_return_val_if_fail(!group->priv->is_writable, NULL);
return group->priv->m2m_table;
}
@@ -114,6 +317,7 @@ static GType
gom_resource_group_get_m2m_type (GomResourceGroup *group)
{
g_return_val_if_fail(GOM_IS_RESOURCE_GROUP(group), 0);
+ g_return_val_if_fail(!group->priv->is_writable, 0);
return group->priv->m2m_type;
}
@@ -327,6 +531,7 @@ gom_resource_group_fetch_sync (GomResourceGroup *group,
GomAdapter *adapter;
g_return_val_if_fail(GOM_IS_RESOURCE_GROUP(group), FALSE);
+ g_return_val_if_fail(!group->priv->is_writable, FALSE);
queue = g_async_queue_new();
@@ -362,6 +567,7 @@ gom_resource_group_fetch_async (GomResourceGroup *group,
g_return_if_fail(GOM_IS_RESOURCE_GROUP(group));
g_return_if_fail(callback != NULL);
+ g_return_if_fail(!group->priv->is_writable);
priv = group->priv;
@@ -384,6 +590,7 @@ gom_resource_group_fetch_finish (GomResourceGroup *group,
g_return_val_if_fail(GOM_IS_RESOURCE_GROUP(group), FALSE);
g_return_val_if_fail(G_IS_SIMPLE_ASYNC_RESULT(simple), FALSE);
+ g_return_val_if_fail(!group->priv->is_writable, FALSE);
if (!(ret = g_simple_async_result_get_op_res_gboolean(simple))) {
g_simple_async_result_propagate_error(simple, error);
@@ -411,6 +618,7 @@ gom_resource_group_get_index (GomResourceGroup *group,
GomResourceGroupPrivate *priv;
g_return_val_if_fail(GOM_IS_RESOURCE_GROUP(group), NULL);
+ g_return_val_if_fail(!group->priv->is_writable, NULL);
priv = group->priv;
@@ -436,6 +644,7 @@ gom_resource_group_finalize (GObject *object)
g_clear_object(&priv->repository);
g_clear_object(&priv->filter);
g_clear_pointer(&priv->items, g_hash_table_unref);
+ g_clear_pointer(&priv->to_write, g_ptr_array_unref);
G_OBJECT_CLASS(gom_resource_group_parent_class)->finalize(object);
}
@@ -476,6 +685,9 @@ gom_resource_group_get_property (GObject *object,
case PROP_RESOURCE_TYPE:
g_value_set_gtype(value, gom_resource_group_get_resource_type(group));
break;
+ case PROP_IS_WRITABLE:
+ g_value_set_boolean(value, group->priv->is_writable);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
}
@@ -517,6 +729,9 @@ gom_resource_group_set_property (GObject *object,
case PROP_REPOSITORY:
gom_resource_group_set_repository(group, g_value_get_object(value));
break;
+ case PROP_IS_WRITABLE:
+ group->priv->is_writable = g_value_get_boolean(value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
}
@@ -594,6 +809,15 @@ gom_resource_group_class_init (GomResourceGroupClass *klass)
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_property(object_class, PROP_RESOURCE_TYPE,
gParamSpecs[PROP_RESOURCE_TYPE]);
+
+ gParamSpecs[PROP_IS_WRITABLE] =
+ g_param_spec_boolean("is-writable",
+ _("Is Writable"),
+ _("Whether the group contains resources to be written."),
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
+ g_object_class_install_property(object_class, PROP_IS_WRITABLE,
+ gParamSpecs[PROP_IS_WRITABLE]);
}
/**
diff --git a/gom/gom-resource-group.h b/gom/gom-resource-group.h
index 739d150..c8d99b7 100644
--- a/gom/gom-resource-group.h
+++ b/gom/gom-resource-group.h
@@ -35,6 +35,7 @@ typedef struct _GomResourceGroup GomResourceGroup;
typedef struct _GomResourceGroupClass GomResourceGroupClass;
typedef struct _GomResourceGroupPrivate GomResourceGroupPrivate;
+#include "gom-repository.h"
#include "gom-resource.h"
struct _GomResourceGroup
@@ -50,6 +51,18 @@ struct _GomResourceGroupClass
GObjectClass parent_class;
};
+GomResourceGroup *gom_resource_group_new (GomRepository *repository);
+gboolean gom_resource_group_append (GomResourceGroup *group,
+ GomResource *resource);
+gboolean gom_resource_group_write_sync (GomResourceGroup *group,
+ GError **error);
+void gom_resource_group_write_async (GomResourceGroup *group,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean gom_resource_group_write_finish (GomResourceGroup *group,
+ GAsyncResult *result,
+ GError **error);
+
void gom_resource_group_fetch_async (GomResourceGroup *group,
guint index_,
guint count,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]