[gegl/swap-backend: 3/4] buffer: moved IO code from swap backend to new class GeglAIOFile. Changed swap backend's queue limit
- From: Ville Sokk <villesokk src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl/swap-backend: 3/4] buffer: moved IO code from swap backend to new class GeglAIOFile. Changed swap backend's queue limit
- Date: Fri, 15 Feb 2013 19:46:12 +0000 (UTC)
commit 39c5c65aa5b2d0f1cc0c0a70705793012789b122
Author: Ville Sokk <ville sokk gmail com>
Date: Tue Jan 29 20:44:52 2013 +0200
buffer: moved IO code from swap backend to new class GeglAIOFile. Changed swap backend's queue limit to
used memory instead of number of entries. Removed unnecessary code from gegl-buffer-load.c
gegl/buffer/Makefile.am | 74 ++-
gegl/buffer/gegl-aio-file.c | 618 ++++++++++++++++++
gegl/buffer/gegl-aio-file.h | 73 +++
gegl/buffer/gegl-buffer-index.h | 6 +-
gegl/buffer/gegl-buffer-load.c | 122 ++---
gegl/buffer/gegl-tile-backend-file-async.c | 14 +-
gegl/buffer/gegl-tile-backend-swap.c | 966 ++++++++++++++++------------
gegl/buffer/gegl-tile-backend-swap.h | 16 +-
gegl/gegl-config.c | 24 +-
gegl/gegl-config.h | 2 +-
gegl/gegl-init.c | 18 +-
11 files changed, 1351 insertions(+), 582 deletions(-)
---
diff --git a/gegl/buffer/Makefile.am b/gegl/buffer/Makefile.am
index 22a5d8d..43d9a5d 100644
--- a/gegl/buffer/Makefile.am
+++ b/gegl/buffer/Makefile.am
@@ -14,72 +14,74 @@ AM_CFLAGS = $(DEP_CFLAGS) $(BABL_CFLAGS)
noinst_LTLIBRARIES = libbuffer.la
libbuffer_la_SOURCES = \
- gegl-tile-backend-tiledir.c \
- gegl-buffer.c \
+ gegl-aio-file.c \
+ gegl-buffer-load.c \
+ gegl-tile-backend-swap.c \
gegl-buffer-access.c \
- gegl-buffer-share.c \
+ gegl-buffer-cl-cache.c \
+ gegl-buffer-cl-iterator.c \
gegl-buffer-index.h \
gegl-buffer-iterator.c \
- gegl-buffer-cl-iterator.c \
- gegl-buffer-cl-cache.c \
gegl-buffer-linear.c \
- gegl-buffer-load.c \
gegl-buffer-save.c \
+ gegl-buffer-share.c \
+ gegl-buffer.c \
gegl-cache.c \
- gegl-sampler.c \
+ gegl-id-pool.c \
+ gegl-region-generic.c \
gegl-sampler-cubic.c \
gegl-sampler-linear.c \
- gegl-sampler-nearest.c \
- gegl-sampler-nohalo.c \
gegl-sampler-lohalo.c \
- gegl-region-generic.c \
- gegl-tile.c \
- gegl-tile-source.c \
- gegl-tile-storage.c \
- gegl-tile-backend.c \
+ gegl-sampler-nearest.c \
+ gegl-sampler-nohalo.c \
+ gegl-sampler.c \
gegl-tile-backend-ram.c \
- gegl-tile-backend-swap.c \
- gegl-tile-handler.c \
- gegl-tile-handler-private.h \
+ gegl-tile-backend-tiledir.c \
+ gegl-tile-backend.c \
gegl-tile-handler-cache.c \
gegl-tile-handler-chain.c \
gegl-tile-handler-empty.c \
gegl-tile-handler-log.c \
+ gegl-tile-handler-private.h \
gegl-tile-handler-zoom.c \
- gegl-id-pool.c \
+ gegl-tile-handler.c \
+ gegl-tile-source.c \
+ gegl-tile-storage.c \
+ gegl-tile.c \
\
- gegl-buffer.h \
- gegl-buffer-private.h \
- gegl-buffer-iterator.h \
- gegl-buffer-cl-iterator.h \
+ gegl-aio-file.h \
+ gegl-tile-backend-swap.h \
gegl-buffer-cl-cache.h \
+ gegl-buffer-cl-iterator.h \
+ gegl-buffer-iterator.h \
gegl-buffer-load.h \
+ gegl-buffer-private.h \
gegl-buffer-save.h \
gegl-buffer-types.h \
+ gegl-buffer.h \
gegl-cache.h \
- gegl-sampler.h \
+ gegl-id-pool.h \
+ gegl-region-generic.h \
+ gegl-region.h \
gegl-sampler-cubic.h \
gegl-sampler-linear.h \
- gegl-sampler-nearest.h \
- gegl-sampler-nohalo.h \
gegl-sampler-lohalo.h \
- gegl-region.h \
- gegl-region-generic.h \
- gegl-tile.h \
- gegl-tile-source.h \
- gegl-tile-storage.h \
- gegl-tile-backend.h \
+ gegl-sampler-nearest.h \
+ gegl-sampler-nohalo.h \
+ gegl-sampler.h \
gegl-tile-backend-file.h \
- gegl-tile-backend-swap.h \
- gegl-tile-backend-tiledir.h \
gegl-tile-backend-ram.h \
- gegl-tile-handler.h \
- gegl-tile-handler-chain.h \
+ gegl-tile-backend-tiledir.h \
+ gegl-tile-backend.h \
gegl-tile-handler-cache.h \
+ gegl-tile-handler-chain.h \
gegl-tile-handler-empty.h \
gegl-tile-handler-log.h \
gegl-tile-handler-zoom.h \
- gegl-id-pool.h
+ gegl-tile-handler.h \
+ gegl-tile-source.h \
+ gegl-tile-storage.h \
+ gegl-tile.h
libbuffer_la_SOURCES += gegl-tile-backend-file-async.c
#if HAVE_64_BIT
diff --git a/gegl/buffer/gegl-aio-file.c b/gegl/buffer/gegl-aio-file.c
new file mode 100644
index 0000000..9a05c53
--- /dev/null
+++ b/gegl/buffer/gegl-aio-file.c
@@ -0,0 +1,618 @@
+/* This file is part of GEGL.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GEGL; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2006, 2007, 2008 Ãyvind KolÃs <pippin gimp org>
+ * 2012 Ville Sokk <ville sokk gmail com>
+ */
+
+
+#include "config.h"
+
+#include <fcntl.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <string.h>
+#include <errno.h>
+
+#ifdef G_OS_WIN32
+#include <process.h>
+#define getpid() _getpid()
+#endif
+
+#include <glib-object.h>
+#include <glib/gprintf.h>
+#include <glib/gstdio.h>
+
+#include "gegl.h"
+#include "gegl-buffer-backend.h"
+#include "gegl-aio-file.h"
+#include "gegl-debug.h"
+#include "gegl-config.h"
+
+#ifndef HAVE_FSYNC
+
+#ifdef G_OS_WIN32
+#define fsync _commit
+#endif
+
+#endif
+
+
+G_DEFINE_TYPE (GeglAIOFile, gegl_aio_file, G_TYPE_OBJECT);
+
+static GObjectClass * parent_class = NULL;
+
+
+typedef enum
+{
+ OP_WRITE,
+ OP_TRUNCATE,
+ OP_SYNC
+} ThreadOp;
+
+typedef struct
+{
+ guint64 offset;
+ guint length;
+ GList *link;
+} FileEntry;
+
+typedef struct
+{
+ GeglAIOFile *file;
+ FileEntry *entry;
+ guchar *source;
+ ThreadOp operation;
+} ThreadParams;
+
+enum
+{
+ PROP_0,
+ PROP_PATH
+};
+
+
+static void gegl_aio_file_push_queue (ThreadParams *params);
+static void gegl_aio_file_thread_write (ThreadParams *params);
+static gpointer gegl_aio_file_thread (gpointer ignored);
+static FileEntry *gegl_aio_file_entry_create (guint64 offset,
+ guint length);
+static FileEntry *gegl_aio_file_lookup_entry (GeglAIOFile *self,
+ guint64 offset);
+static guint gegl_aio_file_hashfunc (gconstpointer key);
+static gboolean gegl_aio_file_equalfunc (gconstpointer a,
+ gconstpointer b);
+static GObject *gegl_aio_file_constructor (GType type,
+ guint n_params,
+ GObjectConstructParam *params);
+static void gegl_aio_file_init (GeglAIOFile *self);
+static void gegl_aio_file_ensure_exist (GeglAIOFile *self);
+static void gegl_aio_file_class_init (GeglAIOFileClass *klass);
+static void gegl_aio_file_finalize (GObject *object);
+static void gegl_aio_file_get_property (GObject *gobject,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void gegl_aio_file_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec);
+void gegl_aio_file_cleanup (void);
+
+
+static GThread *writer_thread = NULL;
+static GQueue *queue = NULL;
+static ThreadParams *in_progress = NULL;
+static gboolean exit_thread = FALSE;
+static guint64 queue_size = 0;
+static GCond empty_cond;
+static GCond max_cond;
+static GMutex mutex;
+
+
+static gpointer
+gegl_aio_file_thread (gpointer ignored)
+{
+ while (TRUE)
+ {
+ ThreadParams *params;
+
+ g_mutex_lock (&mutex);
+
+ while (g_queue_is_empty (queue) && !exit_thread)
+ g_cond_wait (&empty_cond, &mutex);
+
+ if (exit_thread)
+ {
+ g_mutex_unlock (&mutex);
+ /*GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "exiting writer thread");*/
+ return NULL;
+ }
+
+ params = (ThreadParams *)g_queue_pop_head (queue);
+ if (params->operation == OP_WRITE)
+ {
+ g_hash_table_remove (params->file->index, params->entry);
+ in_progress = params;
+ params->entry->link = NULL;
+ }
+
+ g_mutex_unlock (&mutex);
+
+ switch (params->operation)
+ {
+ case OP_WRITE:
+ gegl_aio_file_thread_write (params);
+ break;
+ case OP_TRUNCATE:
+ ftruncate (params->file->out_fd, params->file->total);
+ break;
+ case OP_SYNC:
+ fsync (params->file->out_fd);
+ break;
+ }
+
+ g_mutex_lock (&mutex);
+
+ in_progress = NULL;
+
+ if (params->operation == OP_WRITE)
+ {
+ queue_size -= params->entry->length + sizeof (GList) +
+ sizeof (ThreadParams);
+ g_free (params->source);
+ g_slice_free (FileEntry, params->entry);
+
+ /* unblock the main thread if the queue had gotten too big */
+ if (queue_size <= gegl_config ()->queue_size)
+ g_cond_signal (&max_cond);
+ }
+
+ g_slice_free (ThreadParams, params);
+
+ g_mutex_unlock (&mutex);
+ }
+
+ return NULL;
+}
+
+static void
+gegl_aio_file_push_queue (ThreadParams *params)
+{
+ g_mutex_lock (&mutex);
+
+ /* block if the queue has gotten too big */
+ while (queue_size > gegl_config ()->queue_size)
+ g_cond_wait (&max_cond, &mutex);
+
+ g_queue_push_tail (queue, params);
+
+ if (params->operation == OP_WRITE)
+ {
+ params->entry->link = g_queue_peek_tail_link (queue);
+ queue_size += params->entry->length + sizeof (GList) + sizeof (ThreadParams);
+ }
+
+ /* wake up the writer thread */
+ g_cond_signal (&empty_cond);
+
+ g_mutex_unlock (&mutex);
+}
+
+static void
+gegl_aio_file_thread_write (ThreadParams *params)
+{
+ GeglAIOFile *file = params->file;
+ guint to_be_written = params->entry->length;
+ guint64 offset = params->entry->offset;
+
+ if (file->out_offset != offset)
+ {
+ if (lseek (file->out_fd, offset, SEEK_SET) < 0)
+ {
+ g_warning ("unable to seek to tile in buffer: %s", g_strerror (errno));
+ return;
+ }
+ file->out_offset = offset;
+ }
+
+ while (to_be_written > 0)
+ {
+ gint wrote;
+ wrote = write (file->out_fd,
+ params->source + params->entry->length - to_be_written,
+ to_be_written);
+ if (wrote <= 0)
+ {
+ g_message ("unable to write tile data to self: "
+ "%s (%d/%d bytes written)",
+ g_strerror (errno), wrote, to_be_written);
+ break;
+ }
+
+ to_be_written -= wrote;
+ file->out_offset += wrote;
+ }
+
+ /*GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "writer thread wrote at %i", (gint)offset);*/
+}
+
+static FileEntry *
+gegl_aio_file_entry_create (guint64 offset,
+ guint length)
+{
+ FileEntry *entry = g_slice_new (FileEntry);
+
+ entry->offset = offset;
+ entry->length = length;
+ entry->link = NULL;
+
+ return entry;
+}
+
+static FileEntry *
+gegl_aio_file_lookup_entry (GeglAIOFile *self,
+ guint64 offset)
+{
+ FileEntry *ret = NULL;
+ FileEntry *key = gegl_aio_file_entry_create (offset, 0);
+
+ ret = g_hash_table_lookup (self->index, key);
+ g_slice_free (FileEntry, key);
+
+ return ret;
+}
+
+void
+gegl_aio_file_resize (GeglAIOFile *self,
+ guint64 size)
+{
+ ThreadParams *params;
+
+ self->total = size;
+ params = g_slice_new0 (ThreadParams);
+ params->file = self;
+ params->operation = OP_TRUNCATE;
+
+ gegl_aio_file_push_queue (params);
+}
+
+void
+gegl_aio_file_read (GeglAIOFile *self,
+ guint64 offset,
+ guint length,
+ guchar *dest)
+{
+ FileEntry *entry;
+ guint to_be_read = length;
+ ThreadParams *params = NULL;
+
+ gegl_aio_file_ensure_exist (self);
+
+ g_mutex_lock (&mutex);
+
+ entry = gegl_aio_file_lookup_entry (self, offset);
+
+ if (entry && entry->link)
+ params = entry->link->data;
+ else if (in_progress && in_progress->entry->offset == offset &&
+ in_progress->operation == OP_WRITE)
+ params = in_progress;
+
+ if (params)
+ {
+ if (params->entry->length >= length)
+ {
+ memcpy (dest, params->source, length);
+ g_mutex_unlock (&mutex);
+ return;
+ }
+ else
+ {
+ guint len = params->entry->length;
+
+ memcpy (dest, params->source, len);
+ offset += len;
+ to_be_read -= len;
+ }
+ }
+
+ g_mutex_unlock (&mutex);
+
+ if (self->in_offset != offset)
+ {
+ if (lseek (self->in_fd, offset, SEEK_SET) < 0)
+ {
+ g_warning ("unable to seek to tile in buffer: %s", g_strerror (errno));
+ return;
+ }
+ self->in_offset = offset;
+ }
+
+ while (to_be_read > 0)
+ {
+ GError *error = NULL;
+ gint bytes_read;
+
+ bytes_read = read (self->in_fd, dest + length - to_be_read, to_be_read);
+ if (bytes_read <= 0)
+ {
+ g_message ("unable to read tile data from file %s: "
+ "%s (%d/%d bytes read) %s",
+ self->path, g_strerror (errno), bytes_read, to_be_read,
+ error?error->message:"--");
+ return;
+ }
+ to_be_read -= bytes_read;
+ self->in_offset += bytes_read;
+ }
+}
+
+void
+gegl_aio_file_write (GeglAIOFile *self,
+ guint64 offset,
+ guint length,
+ guchar *source)
+{
+ FileEntry *entry = NULL;
+ ThreadParams *params;
+ guchar *new_source;
+
+ gegl_aio_file_ensure_exist (self);
+
+ g_mutex_lock (&mutex);
+
+ entry = gegl_aio_file_lookup_entry (self, offset);
+
+ if (entry && entry->link)
+ {
+ params = entry->link->data;
+
+ if (entry->length != length)
+ {
+ if (entry->length < length)
+ params->source = g_realloc (params->source, length);
+
+ entry->length = length;
+ }
+
+ memcpy (params->source, source, length);
+ g_mutex_unlock (&mutex);
+ return;
+ }
+
+ entry = gegl_aio_file_entry_create (offset, length);
+ g_hash_table_insert (self->index, entry, entry);
+
+ g_mutex_unlock (&mutex);
+
+ new_source = g_malloc (length);
+ memcpy (new_source, source, length);
+
+ params = g_slice_new0 (ThreadParams);
+ params->operation = OP_WRITE;
+ params->source = new_source;
+ params->entry = entry;
+ params->file = self;
+
+ gegl_aio_file_push_queue (params);
+}
+
+void
+gegl_aio_file_sync (GeglAIOFile *self)
+{
+ ThreadParams *params = g_slice_new0 (ThreadParams);
+ params->operation = OP_SYNC;
+ params->file = self;
+
+ gegl_aio_file_push_queue (params);
+}
+
+static guint
+gegl_aio_file_hashfunc (gconstpointer key)
+{
+ return ((const FileEntry *) key)->offset;
+}
+
+static gboolean
+gegl_aio_file_equalfunc (gconstpointer a,
+ gconstpointer b)
+{
+ const FileEntry *ea = a;
+ const FileEntry *eb = b;
+
+ if (ea->offset == eb->offset)
+ return TRUE;
+
+ return FALSE;
+}
+
+static void
+gegl_aio_file_init (GeglAIOFile *self)
+{
+ self->index = NULL;
+ self->path = NULL;
+ self->in_fd = self->out_fd = -1;
+ self->in_offset = self->out_offset = 0;
+ self->total = 0;
+}
+
+static GObject *
+gegl_aio_file_constructor (GType type,
+ guint n_params,
+ GObjectConstructParam *params)
+{
+ GObject *object;
+ GeglAIOFile *self;
+
+ object = G_OBJECT_CLASS (parent_class)->constructor (type, n_params, params);
+ self = GEGL_AIO_FILE (object);
+
+ self->index = g_hash_table_new (gegl_aio_file_hashfunc,
+ gegl_aio_file_equalfunc);
+
+ /*GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "constructing swap backend");*/
+
+ return object;
+}
+
+static void
+gegl_aio_file_ensure_exist (GeglAIOFile *self)
+{
+ if (self->in_fd == -1 || self->out_fd == -1)
+ {
+ /*GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "creating swapfile %s", self->path);*/
+
+ self->out_fd = g_open (self->path, O_RDWR|O_CREAT, 0770);
+ self->in_fd = g_open (self->path, O_RDONLY);
+
+ if (self->out_fd == -1 || self->in_fd == -1)
+ g_warning ("Could not open file '%s': %s", self->path, g_strerror (errno));
+ }
+}
+
+static void
+gegl_aio_file_class_init (GeglAIOFileClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ gobject_class->constructor = gegl_aio_file_constructor;
+ gobject_class->finalize = gegl_aio_file_finalize;
+ gobject_class->get_property = gegl_aio_file_get_property;
+ gobject_class->set_property = gegl_aio_file_set_property;
+
+ queue = g_queue_new ();
+
+ writer_thread = g_thread_create_full (gegl_aio_file_thread,
+ NULL, 0, TRUE, TRUE,
+ G_THREAD_PRIORITY_NORMAL, NULL);
+
+ g_object_class_install_property (gobject_class, PROP_PATH,
+ g_param_spec_string ("path",
+ "path",
+ "The base path for this backing file for a buffer",
+ NULL,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE));
+}
+
+static void
+gegl_aio_file_finalize (GObject *object)
+{
+ GeglAIOFile *self = GEGL_AIO_FILE (object);
+
+ if (self->index)
+ {
+ if (g_hash_table_size (self->index) != 0)
+ {
+ GList *entries, *iter;
+
+ g_mutex_lock (&mutex);
+
+ entries = g_hash_table_get_keys (self->index);
+
+ for (iter = entries; iter; iter = iter->next)
+ {
+ FileEntry *entry = iter->data;
+
+ if (entry->link)
+ {
+ g_slice_free (ThreadParams, entry->link->data);
+ g_queue_delete_link (queue, entry->link);
+ }
+
+ g_slice_free (FileEntry, entry);
+ }
+
+ g_list_free (entries);
+
+ g_mutex_unlock (&mutex);
+ }
+
+ g_hash_table_unref (self->index);
+ self->index = NULL;
+
+ g_free (self->path);
+ self->path = NULL;
+
+ close (self->in_fd);
+ self->in_fd = -1;
+
+ close (self->out_fd);
+ self->out_fd = -1;
+ }
+
+ (*G_OBJECT_CLASS (parent_class)->finalize)(object);
+}
+
+static void
+gegl_aio_file_get_property (GObject *gobject,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GeglAIOFile *self = GEGL_AIO_FILE (gobject);
+
+ switch (property_id)
+ {
+ case PROP_PATH:
+ g_value_set_string (value, self->path);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, pspec);
+ break;
+ }
+}
+
+static void
+gegl_aio_file_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GeglAIOFile *self = GEGL_AIO_FILE (object);
+
+ switch (property_id)
+ {
+ case PROP_PATH:
+ self->path = g_value_dup_string (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+void
+gegl_aio_file_cleanup (void)
+{
+ /* check if this class has been used at all before cleaning */
+ if (queue)
+ {
+ exit_thread = TRUE;
+ g_cond_signal (&empty_cond);
+ g_thread_join (writer_thread);
+
+ if (g_queue_get_length (queue) != 0)
+ g_warning ("writer thread queue wasn't empty before freeing\n");
+
+ g_queue_free (queue);
+ }
+}
diff --git a/gegl/buffer/gegl-aio-file.h b/gegl/buffer/gegl-aio-file.h
new file mode 100644
index 0000000..1193d73
--- /dev/null
+++ b/gegl/buffer/gegl-aio-file.h
@@ -0,0 +1,73 @@
+/* This file is part of GEGL.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GEGL; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2012 Ville Sokk <ville sokk gmail com>
+ */
+
+#ifndef __GEGL_AIO_FILE_H__
+#define __GEGL_AIO_FILE_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#define GEGL_TYPE_AIO_FILE (gegl_aio_file_get_type ())
+#define GEGL_AIO_FILE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEGL_TYPE_AIO_FILE, GeglAIOFile))
+#define GEGL_AIO_FILE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GEGL_TYPE_AIO_FILE,
GeglAIOFileClass))
+#define GEGL_IS_AIO_FILE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEGL_TYPE_AIO_FILE))
+#define GEGL_IS_AIO_FILE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GEGL_TYPE_AIO_FILE))
+#define GEGL_AIO_FILE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GEGL_TYPE_AIO_FILE,
GeglAIOFileClass))
+
+
+typedef struct _GeglAIOFile GeglAIOFile;
+typedef struct _GeglAIOFileClass GeglAIOFileClass;
+
+struct _GeglAIOFileClass
+{
+ GObjectClass parent_class;
+};
+
+struct _GeglAIOFile
+{
+ GObject parent_instance;
+ GHashTable *index;
+ gchar *path;
+ gint in_fd;
+ gint out_fd;
+ guint64 in_offset;
+ guint64 out_offset;
+ guint64 total;
+};
+
+GType gegl_aio_file_get_type (void) G_GNUC_CONST;
+
+void gegl_aio_file_resize (GeglAIOFile *self,
+ guint64 size);
+
+void gegl_aio_file_read (GeglAIOFile *self,
+ guint64 offset,
+ guint length,
+ guchar *dest);
+
+void gegl_aio_file_write (GeglAIOFile *self,
+ guint64 offset,
+ guint length,
+ guchar *source);
+
+void gegl_aio_file_sync (GeglAIOFile *self);
+
+G_END_DECLS
+
+#endif
diff --git a/gegl/buffer/gegl-buffer-index.h b/gegl/buffer/gegl-buffer-index.h
index ff0bda0..10116c4 100644
--- a/gegl/buffer/gegl-buffer-index.h
+++ b/gegl/buffer/gegl-buffer-index.h
@@ -125,11 +125,9 @@ void gegl_buffer_header_init (GeglBufferHeader *header,
void gegl_tile_entry_destroy (GeglBufferTile *entry);
GeglBufferItem *gegl_buffer_read_header(int i,
- goffset *offset,
- gchar *map);
+ goffset *offset);
GList *gegl_buffer_read_index (int i,
- goffset *offset,
- gchar *map);
+ goffset *offset);
#define struct_check_padding(type, size) \
if (sizeof (type) != size) \
diff --git a/gegl/buffer/gegl-buffer-load.c b/gegl/buffer/gegl-buffer-load.c
index 8857318..2613453 100644
--- a/gegl/buffer/gegl-buffer-load.c
+++ b/gegl/buffer/gegl-buffer-load.c
@@ -94,37 +94,25 @@ load_info_destroy (LoadInfo *info)
g_slice_free (LoadInfo, info);
}
-/* Reads buffer header from the file descriptor (first argument) or
- * memory mapped file if map argument is not NULL
- */
GeglBufferItem *
gegl_buffer_read_header (int i,
- goffset *offset,
- gchar *map)
+ goffset *offset)
{
goffset placeholder;
GeglBufferItem *ret;
-
if (offset==0)
offset = &placeholder;
- if (map == NULL)
- if(lseek(i, 0, SEEK_SET) == -1)
- g_warning ("failed seeking to %i", 0);
+ if(lseek(i, 0, SEEK_SET) == -1)
+ g_warning ("failed seeking to %i", 0);
*offset = 0;
ret = g_malloc (sizeof (GeglBufferHeader));
- if (map)
- {
- memcpy (ret, map, sizeof (GeglBufferHeader));
- *offset += sizeof (GeglBufferHeader);
- }
- else
- {
- ssize_t sz_read = read(i, ret, sizeof(GeglBufferHeader));
- if (sz_read != -1)
- *offset += sz_read;
- }
+ {
+ ssize_t sz_read = read(i, ret, sizeof(GeglBufferHeader));
+ if (sz_read != -1)
+ *offset += sz_read;
+ }
GEGL_NOTE (GEGL_DEBUG_BUFFER_LOAD, "read header: tile-width: %i tile-height: %i next:%i %ix%i\n",
ret->header.tile_width,
@@ -145,41 +133,30 @@ gegl_buffer_read_header (int i,
}
/* reads a block of information from a geglbuffer that resides in an GInputStream,
- * if offset is NULL it is read from the current offset of the stream. If offset
+ * if offset is NULL it is read from the current offsetition of the stream. If offset
* is passed in the offset stored at the location is used as the initial seeking
* point and will be updated with the offset after the read is completed.
- *
- * If the map argument is not NULL then the block is memcpyd from the passed in
- * memory mapped file.
*/
static GeglBufferItem *read_block (int i,
- goffset *offset,
- gchar *map)
+ goffset *offset)
{
- GeglBufferBlock block;
- GeglBufferItem *ret;
- gsize byte_read = 0;
- gint own_size = 0;
- gsize block_size = sizeof (GeglBufferBlock);
+ GeglBufferBlock block;
+ GeglBufferItem *ret;
+ gsize byte_read = 0;
+ gint own_size=0;
if (*offset==0)
return NULL;
- if (offset && map == NULL)
+ if (offset)
if(lseek(i, *offset, SEEK_SET) == -1)
g_warning ("failed seeking to %i", (gint)*offset);
- if (map)
- {
- memcpy (&block, map + *offset, block_size);
- byte_read += block_size;
- }
- else
- {
- ssize_t sz_read = read (i, &block, block_size);
- if(sz_read != -1)
- byte_read += sz_read;
- }
+ {
+ ssize_t sz_read = read (i, &block, sizeof (GeglBufferBlock));
+ if(sz_read != -1)
+ byte_read += sz_read;
+ }
GEGL_NOTE (GEGL_DEBUG_BUFFER_LOAD, "read block: length:%i next:%i",
block.length, (guint)block.next);
@@ -207,41 +184,25 @@ static GeglBufferItem *read_block (int i,
* versions
*/
ret = g_malloc (own_size);
- memcpy (ret, &block, block_size);
-
- if (map)
- {
- memcpy (((gchar*)ret) + block_size, map + *offset + byte_read,
- own_size - block_size);
- byte_read += own_size - block_size;
- }
- else
- {
- ssize_t sz_read = read (i, ((gchar*)ret) + block_size,
- own_size - block_size);
- if(sz_read != -1)
- byte_read += sz_read;
- }
+ memcpy (ret, &block, sizeof (GeglBufferBlock));
+ {
+ ssize_t sz_read = read (i, ((gchar*)ret) + sizeof(GeglBufferBlock),
+ own_size - sizeof(GeglBufferBlock));
+ if(sz_read != -1)
+ byte_read += sz_read;
+ }
ret->block.length = own_size;
}
else if (block.length < own_size)
{
ret = g_malloc (own_size);
- memcpy (ret, &block, block_size);
-
- if (map)
- {
- memcpy (((gchar*)ret) + block_size, map + *offset + byte_read,
- block.length - block_size);
- byte_read += block.length - block_size;
- }
- else
- {
- ssize_t sz_read = read (i, ((gchar*)ret) + block_size,
- block.length - block_size);
- if(sz_read != -1)
- byte_read += sz_read;
- }
+ memcpy (ret, &block, sizeof (GeglBufferBlock));
+ {
+ ssize_t sz_read = read (i, ret + sizeof(GeglBufferBlock),
+ block.length - sizeof (GeglBufferBlock));
+ if(sz_read != -1)
+ byte_read += sz_read;
+ }
ret->block.length = own_size;
}
else
@@ -254,21 +215,15 @@ static GeglBufferItem *read_block (int i,
return ret;
}
-/* Reads buffer index from the file descriptor (first argument) or
- * memory mapped file if map argument is not NULL
- */
GList *
gegl_buffer_read_index (int i,
- goffset *offset,
- gchar *map)
+ goffset *offset)
/* load the index */
{
GList *ret = NULL;
GeglBufferItem *item;
- for (item = read_block (i, offset, map);
- item;
- item = read_block (i, offset, map))
+ for (item = read_block (i, offset); item; item = read_block (i, offset))
{
g_assert (item);
GEGL_NOTE (GEGL_DEBUG_BUFFER_LOAD,"loaded item: %i, %i, %i offset:%i next:%i", item->tile.x,
@@ -283,7 +238,6 @@ gegl_buffer_read_index (int i,
return ret;
}
-
static void sanity(void) { GEGL_BUFFER_SANITY; }
@@ -312,7 +266,7 @@ gegl_buffer_load (const gchar *path)
}
{
- GeglBufferItem *header = gegl_buffer_read_header (info->i, &info->offset, NULL);
+ GeglBufferItem *header = gegl_buffer_read_header (info->i, &info->offset);
g_assert (header);
/*memcpy (&(info->header), header, sizeof (GeglBufferHeader));*/
info->header = *(&header->header);
@@ -340,7 +294,7 @@ gegl_buffer_load (const gchar *path)
*/
g_assert (babl_format_get_bytes_per_pixel (info->format) == info->header.bytes_per_pixel);
- info->tiles = gegl_buffer_read_index (info->i, &info->offset, NULL);
+ info->tiles = gegl_buffer_read_index (info->i, &info->offset);
/* load each tile */
{
diff --git a/gegl/buffer/gegl-tile-backend-file-async.c b/gegl/buffer/gegl-tile-backend-file-async.c
index 9686f9a..246c4b2 100644
--- a/gegl/buffer/gegl-tile-backend-file-async.c
+++ b/gegl/buffer/gegl-tile-backend-file-async.c
@@ -180,7 +180,7 @@ gegl_tile_backend_file_push_queue (GeglFileBackendThreadParams *params)
length = g_queue_get_length (&queue);
/* block if the queue has gotten too big */
- if (length > gegl_config ()->queue_limit)
+ if (length > gegl_config ()->queue_size)
g_cond_wait (max_cond, mutex);
params->file->pending_ops += 1;
@@ -286,7 +286,7 @@ gegl_tile_backend_file_writer_thread (gpointer ignored)
g_cond_signal (params->file->cond);
/* unblock the main thread if the queue had gotten too big */
- if (g_queue_get_length (&queue) < gegl_config ()->queue_limit)
+ if (g_queue_get_length (&queue) < gegl_config ()->queue_size)
g_cond_signal (max_cond);
if (params->source)
@@ -1028,12 +1028,12 @@ gegl_tile_backend_file_load_index (GeglTileBackendFile *self,
* are added here
*/
/* reload header */
- new_header = gegl_buffer_read_header (self->i, &offset, NULL)->header;
+ new_header = gegl_buffer_read_header (self->i, &offset)->header;
while (new_header.flags & GEGL_FLAG_LOCKED)
{
g_usleep (50000);
- new_header = gegl_buffer_read_header (self->i, &offset, NULL)->header;
+ new_header = gegl_buffer_read_header (self->i, &offset)->header;
}
if (new_header.rev == self->header.rev)
@@ -1049,7 +1049,7 @@ gegl_tile_backend_file_load_index (GeglTileBackendFile *self,
tile_size = gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self));
offset = self->header.next;
- self->tiles = gegl_buffer_read_index (self->i, &offset, NULL);
+ self->tiles = gegl_buffer_read_index (self->i, &offset);
self->in_offset = self->out_offset = -1;
backend = GEGL_TILE_BACKEND (self);
@@ -1173,7 +1173,7 @@ gegl_tile_backend_file_constructor (GType type,
}
self->i = g_open (self->path, O_RDONLY, 0);
- self->header = gegl_buffer_read_header (self->i, &offset, NULL)->header;
+ self->header = gegl_buffer_read_header (self->i, &offset)->header;
self->header.rev = self->header.rev -1;
/* we are overriding all of the work of the actual constructor here,
@@ -1292,7 +1292,7 @@ gegl_tile_backend_file_try_lock (GeglTileBackendFile *self)
{
GeglBufferHeader new_header;
- new_header = gegl_buffer_read_header (self->i, NULL, NULL)->header;
+ new_header = gegl_buffer_read_header (self->i, NULL)->header;
if (new_header.flags & GEGL_FLAG_LOCKED)
{
return FALSE;
diff --git a/gegl/buffer/gegl-tile-backend-swap.c b/gegl/buffer/gegl-tile-backend-swap.c
index e1fbef1..ad91d0d 100644
--- a/gegl/buffer/gegl-tile-backend-swap.c
+++ b/gegl/buffer/gegl-tile-backend-swap.c
@@ -34,11 +34,14 @@
#include <glib-object.h>
#include <glib/gprintf.h>
#include <glib/gstdio.h>
+#include <gio/gio.h>
#include "gegl.h"
#include "gegl-buffer-backend.h"
+#include "gegl-buffer-types.h"
#include "gegl-tile-backend.h"
#include "gegl-tile-backend-swap.h"
+#include "gegl-aio-file.h"
#include "gegl-debug.h"
#include "gegl-config.h"
@@ -57,376 +60,140 @@ G_DEFINE_TYPE (GeglTileBackendSwap, gegl_tile_backend_swap, GEGL_TYPE_TILE_BACKE
static GObjectClass * parent_class = NULL;
-typedef enum
-{
- OP_WRITE,
- OP_TRUNCATE,
-} ThreadOp;
-
typedef struct
{
- guint64 offset;
- GList *link;
- gint x;
- gint y;
- gint z;
+ guint64 offset;
+ gint rev;
+ gint x;
+ gint y;
+ gint z;
} SwapEntry;
typedef struct
{
- SwapEntry *entry;
- gint length;
- guchar *source;
- ThreadOp operation;
-} ThreadParams;
-
-typedef struct
-{
guint64 start;
guint64 end;
} SwapGap;
-
-static void gegl_tile_backend_swap_push_queue (ThreadParams *params);
-static void gegl_tile_backend_swap_write (ThreadParams *params);
-static gpointer gegl_tile_backend_swap_writer_thread (gpointer ignored);
-static void gegl_tile_backend_swap_entry_read (GeglTileBackendSwap *self,
- SwapEntry *entry,
- guchar *dest);
-static void gegl_tile_backend_swap_entry_write (GeglTileBackendSwap *self,
- SwapEntry *entry,
- guchar *source);
-static SwapEntry * gegl_tile_backend_swap_entry_create (gint x,
- gint y,
- gint z);
-static guint64 gegl_tile_backend_swap_find_offset (gint tile_size);
-static SwapGap * gegl_tile_backend_swap_gap_new (guint64 start,
- guint64 end);
-static void gegl_tile_backend_swap_entry_destroy (GeglTileBackendSwap *self,
- SwapEntry *entry);
-static void gegl_tile_backend_swap_resize (guint64 size);
-static SwapEntry * gegl_tile_backend_swap_lookup_entry (GeglTileBackendSwap *self,
- gint x,
- gint y,
- gint z);
-static GeglTile * gegl_tile_backend_swap_get_tile (GeglTileSource *self,
- gint x,
- gint y,
- gint z);
-static gpointer gegl_tile_backend_swap_set_tile (GeglTileSource *self,
- GeglTile *tile,
- gint x,
- gint y,
- gint z);
-static gpointer gegl_tile_backend_swap_void_tile (GeglTileSource *self,
- GeglTile *tile,
- gint x,
- gint y,
- gint z);
-static gpointer gegl_tile_backend_swap_exist_tile (GeglTileSource *self,
- GeglTile *tile,
- gint x,
- gint y,
- gint z);
-static gpointer gegl_tile_backend_swap_command (GeglTileSource *self,
- GeglTileCommand command,
- gint x,
- gint y,
- gint z,
- gpointer data);
-static guint gegl_tile_backend_swap_hashfunc (gconstpointer key);
-static gboolean gegl_tile_backend_swap_equalfunc (gconstpointer a,
- gconstpointer b);
-static GObject * gegl_tile_backend_swap_constructor (GType type,
- guint n_params,
- GObjectConstructParam *params);
-static void gegl_tile_backend_swap_finalize (GObject *object);
-static void gegl_tile_backend_swap_ensure_exist (void);
-static void gegl_tile_backend_swap_class_init (GeglTileBackendSwapClass *klass);
-static void gegl_tile_backend_swap_init (GeglTileBackendSwap *self);
-void gegl_tile_backend_swap_cleanup (void);
-
-
-static gchar *path = NULL;
-static gint in_fd = -1;
-static gint out_fd = -1;
-static guint64 in_offset = 0;
-static guint64 out_offset = 0;
-static GList *gap_list = NULL;
-static guint64 total = 0;
-
-static GThread *writer_thread = NULL;
-static GQueue *queue = NULL;
-static GMutex *mutex = NULL;
-static GCond *queue_cond = NULL;
-static GCond *max_cond = NULL;
-static ThreadParams *in_progress = NULL;
-static gboolean exit_thread = FALSE;
-
-
-static void
-gegl_tile_backend_swap_push_queue (ThreadParams *params)
-{
- guint length;
-
- g_mutex_lock (mutex);
-
- length = g_queue_get_length (queue);
-
- /* block if the queue has gotten too big */
- if (length > gegl_config ()->queue_limit)
- g_cond_wait (max_cond, mutex);
-
- g_queue_push_tail (queue, params);
-
- if (params->operation == OP_WRITE)
- params->entry->link = g_queue_peek_tail_link (queue);
-
- /* wake up the writer thread */
- g_cond_signal (queue_cond);
-
- g_mutex_unlock (mutex);
-}
-
-static void
-gegl_tile_backend_swap_write (ThreadParams *params)
-{
- gint to_be_written = params->length;
- guint64 offset = params->entry->offset;
-
- if (out_offset != offset)
- {
- if (lseek (out_fd, offset, SEEK_SET) < 0)
- {
- g_warning ("unable to seek to tile in buffer: %s", g_strerror (errno));
- return;
- }
- out_offset = offset;
- }
-
- while (to_be_written > 0)
- {
- gint wrote;
- wrote = write (out_fd,
- params->source + params->length - to_be_written,
- to_be_written);
- if (wrote <= 0)
- {
- g_message ("unable to write tile data to self: "
- "%s (%d/%d bytes written)",
- g_strerror (errno), wrote, to_be_written);
- break;
- }
-
- to_be_written -= wrote;
- out_offset += wrote;
- }
-
- GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "writer thread wrote at %i", (gint)offset);
-}
-
-static gpointer
-gegl_tile_backend_swap_writer_thread (gpointer ignored)
-{
- while (TRUE)
- {
- ThreadParams *params;
-
- g_mutex_lock (mutex);
-
- while (g_queue_is_empty (queue) && !exit_thread)
- g_cond_wait (queue_cond, mutex);
-
- if (exit_thread)
- {
- g_mutex_unlock (mutex);
- GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "exiting writer thread");
- return NULL;
- }
-
- params = (ThreadParams *)g_queue_pop_head (queue);
- if (params->operation == OP_WRITE)
- {
- in_progress = params;
- params->entry->link = NULL;
- }
-
- g_mutex_unlock (mutex);
-
- switch (params->operation)
- {
- case OP_WRITE:
- gegl_tile_backend_swap_write (params);
- break;
- case OP_TRUNCATE:
- ftruncate (out_fd, total);
- break;
- }
-
- g_mutex_lock (mutex);
- in_progress = NULL;
-
- /* unblock the main thread if the queue had gotten too big */
- if (g_queue_get_length (queue) < gegl_config ()->queue_limit)
- g_cond_signal (max_cond);
-
- if (params->source)
- g_free (params->source);
-
- g_free (params);
-
- g_mutex_unlock (mutex);
- }
-
- return NULL;
-}
-
-static void
-gegl_tile_backend_swap_entry_read (GeglTileBackendSwap *self,
- SwapEntry *entry,
- guchar *dest)
-{
- gint tile_size = gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self));
- gint to_be_read = tile_size;
- guint64 offset = entry->offset;
-
- gegl_tile_backend_swap_ensure_exist ();
-
- if (entry->link || in_progress)
- {
- ThreadParams *queued_op = NULL;
- g_mutex_lock (mutex);
-
- if (entry->link)
- queued_op = entry->link->data;
- else if (in_progress && in_progress->entry == entry)
- queued_op = in_progress;
-
- if (queued_op)
- {
- memcpy (dest, queued_op->source, to_be_read);
- g_mutex_unlock (mutex);
-
- GEGL_NOTE(GEGL_DEBUG_TILE_BACKEND, "read entry %i, %i, %i from queue", entry->x, entry->y,
entry->z);
-
- return;
- }
-
- g_mutex_unlock (mutex);
- }
-
- if (in_offset != offset)
- {
- if (lseek (in_fd, offset, SEEK_SET) < 0)
- {
- g_warning ("unable to seek to tile in buffer: %s", g_strerror (errno));
- return;
- }
- in_offset = offset;
- }
-
- while (to_be_read > 0)
- {
- GError *error = NULL;
- gint byte_read;
-
- byte_read = read (in_fd, dest + tile_size - to_be_read, to_be_read);
- if (byte_read <= 0)
- {
- g_message ("unable to read tile data from swap: "
- "%s (%d/%d bytes read) %s",
- g_strerror (errno), byte_read, to_be_read, error?error->message:"--");
- return;
- }
- to_be_read -= byte_read;
- in_offset += byte_read;
- }
-
- GEGL_NOTE(GEGL_DEBUG_TILE_BACKEND, "read entry %i, %i, %i from %i", entry->x, entry->y, entry->z,
(gint)offset);
-}
-
-static void
-gegl_tile_backend_swap_entry_write (GeglTileBackendSwap *self,
- SwapEntry *entry,
- guchar *source)
+enum
{
- ThreadParams *params;
- gint length = gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self));
- guchar *new_source;
-
- gegl_tile_backend_swap_ensure_exist ();
-
- if (entry->link)
- {
- g_mutex_lock (mutex);
-
- if (entry->link)
- {
- params = entry->link->data;
- memcpy (params->source, source, length);
- g_mutex_unlock (mutex);
-
- GEGL_NOTE(GEGL_DEBUG_TILE_BACKEND, "overwrote queue entry %i, %i, %i at %i", entry->x, entry->y,
entry->z, (gint)entry->offset);
-
- return;
- }
-
- g_mutex_unlock (mutex);
- }
-
- new_source = g_malloc (length);
- memcpy (new_source, source, length);
-
- params = g_new0 (ThreadParams, 1);
- params->operation = OP_WRITE;
- params->length = length;
- params->source = new_source;
- params->entry = entry;
-
- gegl_tile_backend_swap_push_queue (params);
-
- GEGL_NOTE(GEGL_DEBUG_TILE_BACKEND, "pushed write of entry %i, %i, %i at %i", entry->x, entry->y, entry->z,
(gint)entry->offset);
-}
-
-static SwapEntry *
+ PROP_0,
+ PROP_PATH
+};
+
+
+static inline SwapEntry *gegl_tile_backend_swap_entry_create (gint x,
+ gint y,
+ gint z);
+static guint64 gegl_tile_backend_swap_find_offset (GeglTileBackendSwap *self,
+ gint size);
+static inline SwapGap * gegl_tile_backend_swap_gap_new (guint64 start,
+ guint64 end);
+static void gegl_tile_backend_swap_entry_destroy (GeglTileBackendSwap *self,
+ SwapEntry *entry);
+static inline SwapEntry *gegl_tile_backend_swap_lookup_entry (GeglTileBackendSwap *self,
+ gint x,
+ gint y,
+ gint z);
+static GeglTile * gegl_tile_backend_swap_get_tile (GeglTileSource *self,
+ gint x,
+ gint y,
+ gint z);
+static gpointer gegl_tile_backend_swap_set_tile (GeglTileSource *self,
+ GeglTile *tile,
+ gint x,
+ gint y,
+ gint z);
+static gpointer gegl_tile_backend_swap_void_tile (GeglTileSource *self,
+ GeglTile *tile,
+ gint x,
+ gint y,
+ gint z);
+static GeglBufferHeader gegl_tile_backend_swap_read_header (GeglTileBackendSwap *self);
+static void gegl_tile_backend_swap_write_header (GeglTileBackendSwap *self);
+static GList* gegl_tile_backend_swap_read_index (GeglTileBackendSwap *self);
+static void gegl_tile_backend_swap_load_index (GeglTileBackendSwap *self);
+static gpointer gegl_tile_backend_swap_flush (GeglTileSource *source);
+static gpointer gegl_tile_backend_swap_exist_tile (GeglTileSource *self,
+ GeglTile *tile,
+ gint x,
+ gint y,
+ gint z);
+static gpointer gegl_tile_backend_swap_command (GeglTileSource *self,
+ GeglTileCommand command,
+ gint x,
+ gint y,
+ gint z,
+ gpointer data);
+static void gegl_tile_backend_swap_file_changed (GFileMonitor *monitor,
+ GFile *file,
+ GFile *other_file,
+ GFileMonitorEvent event_type,
+ GeglTileBackendSwap *self);
+static guint gegl_tile_backend_swap_hashfunc (gconstpointer key);
+static gboolean gegl_tile_backend_swap_equalfunc (gconstpointer a,
+ gconstpointer b);
+static GObject * gegl_tile_backend_swap_constructor (GType type,
+ guint n_params,
+ GObjectConstructParam *params);
+static void gegl_tile_backend_swap_finalize (GObject *object);
+static void gegl_tile_backend_swap_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gegl_tile_backend_swap_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void gegl_tile_backend_swap_class_init (GeglTileBackendSwapClass *klass);
+static void gegl_tile_backend_swap_init (GeglTileBackendSwap *self);
+void gegl_tile_backend_swap_cleanup (void);
+
+
+
+GeglAIOFile *swap_file = NULL;
+GList *swap_gap_list = NULL;
+
+
+static inline SwapEntry *
gegl_tile_backend_swap_entry_create (gint x,
gint y,
gint z)
{
- SwapEntry *entry = g_new0 (SwapEntry, 1);
+ SwapEntry *entry = g_slice_new0 (SwapEntry);
- entry->x = x;
- entry->y = y;
- entry->z = z;
- entry->link = NULL;
+ entry->x = x;
+ entry->y = y;
+ entry->z = z;
return entry;
}
static guint64
-gegl_tile_backend_swap_find_offset (gint tile_size)
+gegl_tile_backend_swap_find_offset (GeglTileBackendSwap *self,
+ gint size)
{
SwapGap *gap;
guint64 offset;
- if (gap_list)
+ if (*self->gap_list)
{
- GList *link = gap_list;
+ GList *link = *self->gap_list;
while (link)
{
gap = link->data;
- if ((gap->end - gap->start) >= tile_size)
+ if ((gap->end - gap->start) >= size)
{
guint64 offset = gap->start;
- gap->start += tile_size;
+ gap->start += size;
if (gap->start == gap->end)
{
g_slice_free (SwapGap, gap);
- gap_list = g_list_remove_link (gap_list, link);
+ *self->gap_list = g_list_remove_link (*self->gap_list, link);
g_list_free (link);
}
@@ -437,14 +204,16 @@ gegl_tile_backend_swap_find_offset (gint tile_size)
}
}
- offset = total;
+ offset = self->file->total;
+
+ gegl_aio_file_resize (self->file, self->file->total + size + 32 * 4 * 4 * 128 * 64);
- gegl_tile_backend_swap_resize (total + 32 * tile_size);
+ GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "pushed resize to %i", (gint)self->file->total);
return offset;
}
-static SwapGap *
+static inline SwapGap *
gegl_tile_backend_swap_gap_new (guint64 start,
guint64 end)
{
@@ -461,35 +230,15 @@ gegl_tile_backend_swap_entry_destroy (GeglTileBackendSwap *self,
SwapEntry *entry)
{
guint64 start, end;
- guint64 *offset = g_new (guint64, 1);
gint tile_size = gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self));
GList *link, *link2;
SwapGap *gap, *gap2;
- *offset = entry->offset;
-
- if (entry->link)
- {
- link = entry->link;
-
- g_mutex_lock (mutex);
-
- if (link)
- {
- ThreadParams *queued_op = link->data;
- g_queue_delete_link (queue, link);
- g_free (queued_op->source);
- g_free (queued_op);
- }
-
- g_mutex_unlock (mutex);
- }
-
start = entry->offset;
end = start + tile_size;
- link = gap_list;
- while (gap_list)
+ link = *self->gap_list;
+ while (link)
{
gap = link->data;
@@ -505,7 +254,7 @@ gegl_tile_backend_swap_entry_destroy (GeglTileBackendSwap *self,
{
gap2->end = gap->end;
g_slice_free (SwapGap, gap);
- gap_list = g_list_remove_link (gap_list, link);
+ *self->gap_list = g_list_remove_link (*self->gap_list, link);
g_list_free (link);
}
}
@@ -523,7 +272,8 @@ gegl_tile_backend_swap_entry_destroy (GeglTileBackendSwap *self,
{
gap2->start = gap->start;
g_slice_free (SwapGap, gap);
- gap_list = g_list_remove_link (gap_list, link);
+ *self->gap_list =
+ g_list_remove_link (*self->gap_list, link);
g_list_free (link);
}
}
@@ -532,17 +282,17 @@ gegl_tile_backend_swap_entry_destroy (GeglTileBackendSwap *self,
else if (end < gap->start)
{
gap = gegl_tile_backend_swap_gap_new (start, end);
+
link2 = g_list_alloc ();
link2->data = gap;
link2->next = link;
link2->prev = link->prev;
-
if (link->prev)
link->prev->next = link2;
link->prev = link2;
- if (link == gap_list)
- gap_list = link2;
+ if (link == *self->gap_list)
+ *self->gap_list = link2;
break;
}
else if (!link->next)
@@ -557,42 +307,28 @@ gegl_tile_backend_swap_entry_destroy (GeglTileBackendSwap *self,
link = link->next;
}
- if (!gap_list)
+ if (!*self->gap_list)
{
gap = gegl_tile_backend_swap_gap_new (start, end);
- gap_list = g_list_append (gap_list, gap);
+ *self->gap_list = g_list_append (*self->gap_list, gap);
}
- link = g_list_last (gap_list);
+ link = g_list_last (*self->gap_list);
gap = link->data;
- if (gap->end < total - 32 * tile_size)
+ if (gap->end == self->file->total)
{
- gegl_tile_backend_swap_resize (gap->start + 32 * tile_size);
+ gegl_aio_file_resize (self->file, gap->start);
g_slice_free (SwapGap, gap);
- gap_list = g_list_remove_link (gap_list, link);
+ *self->gap_list = g_list_remove_link (*self->gap_list, link);
g_list_free (link);
}
g_hash_table_remove (self->index, entry);
- g_free (entry);
+ g_slice_free (SwapEntry, entry);
}
-static void
-gegl_tile_backend_swap_resize (guint64 size)
-{
- ThreadParams *params;
-
- total = size;
- params = g_new0 (ThreadParams, 1);
- params->operation = OP_TRUNCATE;
-
- gegl_tile_backend_swap_push_queue (params);
-
- GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "pushed resize to %i", (gint)total);
-}
-
-static SwapEntry *
+static inline SwapEntry *
gegl_tile_backend_swap_lookup_entry (GeglTileBackendSwap *self,
gint x,
gint y,
@@ -602,7 +338,7 @@ gegl_tile_backend_swap_lookup_entry (GeglTileBackendSwap *self,
SwapEntry *key = gegl_tile_backend_swap_entry_create (x, y, z);
ret = g_hash_table_lookup (self->index, key);
- g_free (key);
+ g_slice_free (SwapEntry, key);
return ret;
}
@@ -628,9 +364,13 @@ gegl_tile_backend_swap_get_tile (GeglTileSource *self,
tile_size = gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self));
tile = gegl_tile_new (tile_size);
+ gegl_tile_set_rev (tile, entry->rev);
gegl_tile_mark_as_stored (tile);
- gegl_tile_backend_swap_entry_read (tile_backend_swap, entry, gegl_tile_get_data (tile));
+ gegl_aio_file_read (tile_backend_swap->file, entry->offset, tile_size,
+ gegl_tile_get_data (tile));
+
+ GEGL_NOTE(GEGL_DEBUG_TILE_BACKEND, "read entry %i, %i, %i from %i", entry->x, entry->y, entry->z,
(gint)entry->offset);
return tile;
}
@@ -650,19 +390,22 @@ gegl_tile_backend_swap_set_tile (GeglTileSource *self,
tile_backend_swap = GEGL_TILE_BACKEND_SWAP (backend);
entry = gegl_tile_backend_swap_lookup_entry (tile_backend_swap, x, y, z);
- gegl_tile_backend_swap_ensure_exist ();
-
if (entry == NULL)
{
entry = gegl_tile_backend_swap_entry_create (x, y, z);
- entry->offset = gegl_tile_backend_swap_find_offset (gegl_tile_backend_get_tile_size (backend));
+ entry->offset = gegl_tile_backend_swap_find_offset (tile_backend_swap,
+ gegl_tile_backend_get_tile_size (backend));
g_hash_table_insert (tile_backend_swap->index, entry, entry);
}
- gegl_tile_backend_swap_entry_write (tile_backend_swap, entry, gegl_tile_get_data (tile));
+ gegl_aio_file_write (tile_backend_swap->file, entry->offset,
+ gegl_tile_backend_get_tile_size (backend),
+ gegl_tile_get_data (tile));
gegl_tile_mark_as_stored (tile);
+ GEGL_NOTE(GEGL_DEBUG_TILE_BACKEND, "pushed write of entry %i, %i, %i at %i", entry->x, entry->y, entry->z,
(gint)entry->offset);
+
return NULL;
}
@@ -691,6 +434,211 @@ gegl_tile_backend_swap_void_tile (GeglTileSource *self,
return NULL;
}
+static GeglBufferHeader
+gegl_tile_backend_swap_read_header (GeglTileBackendSwap *self)
+{
+ GeglBufferHeader ret;
+
+ gegl_aio_file_read(self->file, 0, sizeof (GeglBufferHeader), (guchar*)&ret);
+
+ GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "read header: tile-width: %i tile-height: %i next:%i %ix%i\n",
+ ret.tile_width,
+ ret.tile_height,
+ (guint)ret.next,
+ ret.width,
+ ret.height);
+
+ if (!(ret.magic[0]=='G' &&
+ ret.magic[1]=='E' &&
+ ret.magic[2]=='G' &&
+ ret.magic[3]=='L'))
+ {
+ g_warning ("Magic is wrong! %s", ret.magic);
+ }
+
+ return ret;
+}
+
+static void
+gegl_tile_backend_swap_write_header (GeglTileBackendSwap *self)
+{
+ gegl_aio_file_write (self->file, 0, sizeof (GeglBufferHeader), (guchar*)&self->header);
+}
+
+static GList *
+gegl_tile_backend_swap_read_index (GeglTileBackendSwap *self)
+{
+ GList *ret = NULL;
+ guint64 offset = self->header.next;
+ GeglBufferTile *item;
+
+ while (offset) /* ->next of the last block is 0 */
+ {
+ item = g_malloc (sizeof (GeglBufferTile));
+ gegl_aio_file_read (self->file, offset, sizeof (GeglBufferTile), (guchar*)item);
+ offset = item->block.next;
+ ret = g_list_prepend (ret, item);
+ }
+
+ ret = g_list_reverse (ret);
+
+ return ret;
+}
+
+static void
+gegl_tile_backend_swap_load_index (GeglTileBackendSwap *self)
+{
+ GeglBufferHeader new_header;
+ GList *tiles, *iter;
+ GeglTileBackend *backend = GEGL_TILE_BACKEND (self);
+ guint64 max = 0;
+ gint tile_size;
+
+ new_header = gegl_tile_backend_swap_read_header (self);
+
+ while (new_header.flags & GEGL_FLAG_LOCKED)
+ {
+ g_usleep (50000);
+ new_header = gegl_tile_backend_swap_read_header (self);
+ }
+
+ if (new_header.rev == self->header.rev)
+ {
+ GEGL_NOTE(GEGL_DEBUG_TILE_BACKEND, "header not changed: %s", self->path);
+ return;
+ }
+ else
+ {
+ self->header = new_header;
+ GEGL_NOTE(GEGL_DEBUG_TILE_BACKEND, "loading index: %s", self->path);
+ }
+
+ tile_size = gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self));
+ tiles = gegl_tile_backend_swap_read_index (self);
+
+ for (iter = tiles; iter; iter = iter->next)
+ {
+ GeglBufferTile *item = iter->data;
+ SwapEntry *new, *existing =
+ gegl_tile_backend_swap_lookup_entry (self, item->x, item->y, item->z);
+
+ if (item->offset > max)
+ max = item->offset + tile_size;
+
+ if (existing)
+ {
+ if (existing->rev == item->rev)
+ {
+ g_assert (existing->offset == item->offset);
+ g_free (item);
+ continue;
+ }
+ else
+ {
+ GeglTileStorage *storage =
+ (void*) gegl_tile_backend_peek_storage (backend);
+ GeglRectangle rect;
+
+ g_hash_table_remove (self->index, existing);
+ gegl_tile_source_refetch (GEGL_TILE_SOURCE (storage),
+ existing->x,
+ existing->y,
+ existing->z);
+
+ if (existing->z == 0)
+ {
+ rect.width = self->header.tile_width;
+ rect.height = self->header.tile_height;
+ rect.x = existing->x * self->header.tile_width;
+ rect.y = existing->y * self->header.tile_height;
+ }
+ g_free (existing);
+ g_signal_emit_by_name (storage, "changed", &rect, NULL);
+ }
+ }
+
+ /* we've found a new tile */
+ new = gegl_tile_backend_swap_entry_create (item->x, item->y, item->z);
+ new->rev = item->rev;
+ new->offset = item->offset;
+ g_hash_table_insert (self->index, new, new);
+ g_free (item);
+ }
+
+ g_list_free (tiles);
+ g_list_free (*self->gap_list);
+ *self->gap_list = NULL;
+ self->file->total = max;
+}
+
+static gpointer
+gegl_tile_backend_swap_flush (GeglTileSource *source)
+{
+ GeglTileBackend *backend;
+ GeglTileBackendSwap *self;
+ GList *tiles;
+
+ backend = GEGL_TILE_BACKEND (source);
+ self = GEGL_TILE_BACKEND_SWAP (backend);
+
+ GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "flushing %s", self->path);
+
+ self->header.rev++;
+ tiles = g_hash_table_get_keys (self->index);
+
+ if (tiles == NULL)
+ self->header.next = 0;
+ else
+ {
+ GList *iter;
+ guchar *index;
+ guint64 index_offset;
+ gint index_len;
+ GeglBufferBlock *previous = NULL;
+
+ index_len = g_list_length (tiles) * sizeof (GeglBufferTile);
+ index = g_malloc (index_len);
+ index_offset = gegl_tile_backend_swap_find_offset (self, index_len);
+ index_len = 0;
+
+ for (iter = tiles; iter; iter = iter->next)
+ {
+ SwapEntry *item = iter->data;
+ GeglBufferTile entry;
+
+ entry.x = item->x;
+ entry.y = item->y;
+ entry.z = item->z;
+ entry.rev = item->rev;
+ entry.offset = item->offset;
+ entry.block.flags = GEGL_FLAG_TILE;
+ entry.block.length = sizeof (GeglBufferTile);
+
+ memcpy (index + index_len, &entry, sizeof (GeglBufferTile));
+
+ if (previous)
+ previous->next = index_offset + index_len;
+
+ previous = (GeglBufferBlock *)(index + index_len);
+
+ index_len += sizeof (GeglBufferTile);
+ }
+
+ previous->next = 0; /* last block points to offset 0 */
+ self->header.next = index_offset;
+ gegl_aio_file_write (self->file, index_offset, index_len, index);
+ g_free (index);
+ g_list_free (tiles);
+ }
+
+ gegl_tile_backend_swap_write_header (self);
+ gegl_aio_file_sync (self->file);
+
+ GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "flushed %s", self->path);
+
+ return (gpointer)0xf0f;
+}
+
static gpointer
gegl_tile_backend_swap_exist_tile (GeglTileSource *self,
GeglTile *tile,
@@ -709,6 +657,37 @@ gegl_tile_backend_swap_exist_tile (GeglTileSource *self,
return entry!=NULL?((gpointer)0x1):NULL;
}
+gboolean
+gegl_tile_backend_swap_try_lock (GeglTileBackendSwap *self)
+{
+ GeglBufferHeader new_header = gegl_tile_backend_swap_read_header (self);
+
+ if (new_header.flags & GEGL_FLAG_LOCKED)
+ return FALSE;
+
+ self->header.flags += GEGL_FLAG_LOCKED;
+ gegl_tile_backend_swap_write_header (self);
+ gegl_aio_file_sync (self->file);
+
+ return TRUE;
+}
+
+gboolean
+gegl_tile_backend_swap_unlock (GeglTileBackendSwap *self)
+{
+ if (!(self->header.flags & GEGL_FLAG_LOCKED))
+ {
+ g_warning ("tried to unlock unlocked buffer");
+ return FALSE;
+ }
+
+ self->header.flags -= GEGL_FLAG_LOCKED;
+ gegl_tile_backend_swap_write_header (self);
+ gegl_aio_file_sync (self->file);
+
+ return TRUE;
+}
+
static gpointer
gegl_tile_backend_swap_command (GeglTileSource *self,
GeglTileCommand command,
@@ -730,7 +709,7 @@ gegl_tile_backend_swap_command (GeglTileSource *self,
case GEGL_TILE_EXIST:
return gegl_tile_backend_swap_exist_tile (self, data, x, y, z);
case GEGL_TILE_FLUSH:
- return NULL;
+ return gegl_tile_backend_swap_flush (self);
default:
g_assert (command < GEGL_TILE_LAST_COMMAND &&
@@ -739,6 +718,17 @@ gegl_tile_backend_swap_command (GeglTileSource *self,
return FALSE;
}
+static void
+gegl_tile_backend_swap_file_changed (GFileMonitor *monitor,
+ GFile *file,
+ GFile *other_file,
+ GFileMonitorEvent event_type,
+ GeglTileBackendSwap *self)
+{
+ if (event_type == G_FILE_MONITOR_EVENT_CHANGED)
+ gegl_tile_backend_swap_load_index (self);
+}
+
static guint
gegl_tile_backend_swap_hashfunc (gconstpointer key)
{
@@ -794,6 +784,67 @@ gegl_tile_backend_swap_constructor (GType type,
self->index = g_hash_table_new (gegl_tile_backend_swap_hashfunc,
gegl_tile_backend_swap_equalfunc);
+ if (self->path)
+ { /* if the path is specified, use a separate file for this buffer */
+ GeglTileBackend *backend = GEGL_TILE_BACKEND (self);
+
+ self->file = g_object_new (GEGL_TYPE_AIO_FILE, "path", self->path, NULL);
+ self->gap_list = g_malloc (sizeof (void*));
+ *self->gap_list = NULL;
+
+ if (g_access (self->path, F_OK) != -1)
+ {/* if we can access the file, assume that it was created by another
+ process and read it */
+ self->gfile = g_file_new_for_commandline_arg (self->path);
+ self->monitor = g_file_monitor_file (self->gfile,
+ G_FILE_MONITOR_NONE,
+ NULL, NULL);
+ g_signal_connect (self->monitor, "changed",
+ G_CALLBACK (gegl_tile_backend_swap_file_changed),
+ self);
+ self->header = gegl_tile_backend_swap_read_header (self);
+ self->header.rev -= 1;
+
+ /* we are overriding all of the work of the actual constructor here,
+ * a really evil hack :d
+ */
+ backend->priv->tile_width = self->header.tile_width;
+ backend->priv->tile_height = self->header.tile_height;
+ backend->priv->format = babl_format (self->header.description);
+ backend->priv->px_size = babl_format_get_bytes_per_pixel (backend->priv->format);
+ backend->priv->tile_size = backend->priv->tile_width *
+ backend->priv->tile_height *
+ backend->priv->px_size;
+ backend->priv->shared = TRUE;
+
+ gegl_tile_backend_swap_load_index (self);
+ }
+ else
+ {
+ gegl_buffer_header_init (&self->header,
+ backend->priv->tile_width,
+ backend->priv->tile_height,
+ backend->priv->px_size,
+ backend->priv->format);
+ }
+ }
+ else
+ { /* use a file that's shared between multiple buffers */
+ if (swap_file == NULL)
+ {
+ gchar *filename, *path;
+
+ filename = g_strdup_printf ("%i-common-swap-file.swap", getpid ());
+ path = g_build_filename (gegl_config ()->swap, filename, NULL);
+ swap_file = g_object_new (GEGL_TYPE_AIO_FILE, "path", path, NULL);
+ g_free (filename);
+ g_free (path);
+ }
+
+ self->gap_list = &swap_gap_list;
+ self->file = swap_file;
+ }
+
GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "constructing swap backend");
return object;
@@ -823,28 +874,83 @@ gegl_tile_backend_swap_finalize (GObject *object)
self->index = NULL;
}
+ if (self->file && self->file != swap_file)
+ {
+ g_object_unref (self->file);
+ self->file = NULL;
+ }
+
+ if (self->gfile)
+ {
+ g_object_unref (self->gfile);
+ self->gfile = NULL;
+ }
+
+ if (self->monitor)
+ {
+ g_object_unref (self->monitor);
+ self->monitor = NULL;
+ }
+
+ if (self->path)
+ {
+ g_free (self->path);
+ self->path = NULL;
+ }
+
+ if (*self->gap_list && *self->gap_list != swap_gap_list)
+ {
+ GList *iter;
+
+ for (iter = *self->gap_list; iter; iter = iter->next)
+ g_slice_free (SwapGap, iter->data);
+
+ g_list_free (*self->gap_list);
+ *self->gap_list = NULL;
+ }
+
(*G_OBJECT_CLASS (parent_class)->finalize)(object);
}
static void
-gegl_tile_backend_swap_ensure_exist (void)
+gegl_tile_backend_swap_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
{
- if (in_fd == -1 || out_fd == -1)
- {
- gchar *filename = g_strdup_printf ("%i-shared.swap", getpid ());
- path = g_build_filename (gegl_config ()->swap, filename, NULL);
- g_free (filename);
+ GeglTileBackendSwap *self = GEGL_TILE_BACKEND_SWAP (object);
- GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "creating swapfile %s", path);
+ switch (property_id)
+ {
+ case PROP_PATH:
+ self->path = g_value_dup_string (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
- out_fd = g_open (path, O_RDWR|O_CREAT, 0770);
- in_fd = g_open (path, O_RDONLY);
+static void
+gegl_tile_backend_swap_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GeglTileBackendSwap *self = GEGL_TILE_BACKEND_SWAP (object);
- if (out_fd == -1 || in_fd == -1)
- g_warning ("Could not open swap file '%s': %s", path, g_strerror (errno));
+ switch (property_id)
+ {
+ case PROP_PATH:
+ g_value_set_string (value, self->path);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
}
}
+
static void
gegl_tile_backend_swap_class_init (GeglTileBackendSwapClass *klass)
{
@@ -854,40 +960,44 @@ gegl_tile_backend_swap_class_init (GeglTileBackendSwapClass *klass)
gobject_class->constructor = gegl_tile_backend_swap_constructor;
gobject_class->finalize = gegl_tile_backend_swap_finalize;
+ gobject_class->set_property = gegl_tile_backend_swap_set_property;
+ gobject_class->get_property = gegl_tile_backend_swap_get_property;
+
+ g_object_class_install_property (gobject_class, PROP_PATH,
+ g_param_spec_string ("path",
+ "path",
+ "Path of the backing file",
+ NULL,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE));
+}
+
+static void
+gegl_tile_backend_swap_init (GeglTileBackendSwap *self)
+{
+ ((GeglTileSource*)self)->command = gegl_tile_backend_swap_command;
- queue = g_queue_new ();
- queue_cond = g_cond_new ();
- max_cond = g_cond_new ();
- mutex = g_mutex_new ();
- writer_thread = g_thread_create_full (gegl_tile_backend_swap_writer_thread,
- NULL, 0, TRUE, TRUE,
- G_THREAD_PRIORITY_NORMAL, NULL);
+ self->path = NULL;
+ self->file = NULL;
+ self->index = NULL;
+ self->gap_list = NULL;
+ self->gfile = NULL;
+ self->monitor = NULL;
}
void
gegl_tile_backend_swap_cleanup (void)
{
- if (in_fd != -1 && out_fd != -1)
- {
- exit_thread = TRUE;
- g_cond_signal (queue_cond);
- g_thread_join (writer_thread);
+ if (swap_file)
+ g_object_unref (swap_file);
- if (g_queue_get_length (queue) != 0)
- g_warning ("tile-backend-swap writer queue wasn't empty before freeing\n");
+ if (swap_gap_list)
+ {
+ GList *iter;
- g_queue_free (queue);
- g_cond_free (queue_cond);
- g_cond_free (max_cond);
- g_mutex_free (mutex);
+ for (iter = swap_gap_list; iter; iter = iter->next)
+ g_slice_free (SwapGap, iter->data);
- close (in_fd);
- close (out_fd);
+ g_list_free (swap_gap_list);
}
}
-
-static void
-gegl_tile_backend_swap_init (GeglTileBackendSwap *self)
-{
- ((GeglTileSource*)self)->command = gegl_tile_backend_swap_command;
-}
diff --git a/gegl/buffer/gegl-tile-backend-swap.h b/gegl/buffer/gegl-tile-backend-swap.h
index 87a98f1..f4c7d3b 100644
--- a/gegl/buffer/gegl-tile-backend-swap.h
+++ b/gegl/buffer/gegl-tile-backend-swap.h
@@ -21,6 +21,8 @@
#include <glib.h>
#include "gegl-tile-backend.h"
+#include "gegl-buffer-index.h"
+#include "gegl-aio-file.h"
G_BEGIN_DECLS
@@ -42,12 +44,22 @@ struct _GeglTileBackendSwapClass
struct _GeglTileBackendSwap
{
- GeglTileBackend parent_instance;
- GHashTable *index;
+ GeglTileBackend parent_instance;
+ gchar *path;
+ GeglAIOFile *file;
+ GHashTable *index;
+ GList **gap_list;
+ GeglBufferHeader header;
+ GFile *gfile;
+ GFileMonitor *monitor;
};
GType gegl_tile_backend_swap_get_type (void) G_GNUC_CONST;
+gboolean gegl_tile_backend_swap_try_lock (GeglTileBackendSwap *self);
+
+gboolean gegl_tile_backend_swap_unlock (GeglTileBackendSwap *self);
+
G_END_DECLS
#endif
diff --git a/gegl/gegl-config.c b/gegl/gegl-config.c
index 5c156eb..35609a2 100644
--- a/gegl/gegl-config.c
+++ b/gegl/gegl-config.c
@@ -46,7 +46,7 @@ enum
PROP_TILE_HEIGHT,
PROP_THREADS,
PROP_USE_OPENCL,
- PROP_QUEUE_LIMIT
+ PROP_QUEUE_SIZE
};
static void
@@ -99,8 +99,8 @@ gegl_config_get_property (GObject *gobject,
g_value_set_boolean (value, config->use_opencl);
break;
- case PROP_QUEUE_LIMIT:
- g_value_set_int (value, config->queue_limit);
+ case PROP_QUEUE_SIZE:
+ g_value_set_int (value, config->queue_size);
break;
default:
@@ -181,8 +181,8 @@ gegl_config_set_property (GObject *gobject,
gegl_cl_init (NULL);
break;
- case PROP_QUEUE_LIMIT:
- config->queue_limit = g_value_get_int (value);
+ case PROP_QUEUE_SIZE:
+ config->queue_size = g_value_get_uint64 (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, pspec);
@@ -293,13 +293,13 @@ gegl_config_class_init (GeglConfigClass *klass)
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
- g_object_class_install_property (gobject_class, PROP_QUEUE_LIMIT,
- g_param_spec_int ("queue-limit",
- "Queue limit",
- "Maximum number of entries in the file tile backend's
writer queue",
- 2, G_MAXINT, 1000,
- G_PARAM_READWRITE |
- G_PARAM_CONSTRUCT));
+ g_object_class_install_property (gobject_class, PROP_QUEUE_SIZE,
+ g_param_spec_uint64 ("queue-size",
+ "Queue size",
+ "Maximum size of the file backend's thread queue in
megabytes",
+ 2, G_MAXUINT64, 100 * 1024 * 1024,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
}
static void
diff --git a/gegl/gegl-config.h b/gegl/gegl-config.h
index 4d4c3b4..7f9aeac 100644
--- a/gegl/gegl-config.h
+++ b/gegl/gegl-config.h
@@ -44,7 +44,7 @@ struct _GeglConfig
gint tile_height;
gint threads;
gboolean use_opencl;
- gint queue_limit;
+ guint64 queue_size;
};
struct _GeglConfigClass
diff --git a/gegl/gegl-init.c b/gegl/gegl-init.c
index 5c6d15b..776ef16 100644
--- a/gegl/gegl-init.c
+++ b/gegl/gegl-init.c
@@ -202,7 +202,7 @@ static gchar *cmd_gegl_tile_size = NULL;
static gchar *cmd_babl_tolerance = NULL;
static gchar *cmd_gegl_threads = NULL;
static gboolean *cmd_gegl_opencl = NULL;
-static gint *cmd_gegl_queue_limit = NULL;
+static gchar *cmd_gegl_queue_size = NULL;
static const GOptionEntry cmd_entries[]=
{
@@ -247,9 +247,9 @@ static const GOptionEntry cmd_entries[]=
N_("Use OpenCL"), NULL
},
{
- "gegl-queue-limit", 0, 0,
- G_OPTION_ARG_INT, &cmd_gegl_queue_limit,
- N_("Maximum number of entries in the file tile backend's writer queue"), "<count>"
+ "gegl-queue-size", 0, 0,
+ G_OPTION_ARG_INT, &cmd_gegl_queue_size,
+ N_("Maximum size of the file backend's thread queue in megabytes"), "<megabytes>"
},
{ NULL }
};
@@ -303,8 +303,8 @@ GeglConfig *gegl_config (void)
else
config->use_opencl = TRUE;
- if (g_getenv ("GEGL_QUEUE_LIMIT"))
- config->queue_limit = atoi(g_getenv ("GEGL_QUEUE_LIMIT"));
+ if (g_getenv ("GEGL_QUEUE_SIZE"))
+ config->queue_size = atoll(g_getenv ("GEGL_QUEUE_SIZE")) * 1024 * 1024;
if (gegl_swap_dir())
config->swap = g_strdup(gegl_swap_dir ());
@@ -355,6 +355,7 @@ static void swap_clean (void)
}
void gegl_tile_storage_cache_cleanup (void);
+void gegl_aio_file_cleanup (void);
void gegl_tile_backend_swap_cleanup (void);
void
@@ -371,6 +372,7 @@ gegl_exit (void)
timing = gegl_ticks ();
gegl_tile_backend_swap_cleanup ();
+ gegl_aio_file_cleanup ();
gegl_tile_storage_cache_cleanup ();
gegl_tile_cache_destroy ();
gegl_operation_gtype_cleanup ();
@@ -520,8 +522,8 @@ gegl_post_parse_hook (GOptionContext *context,
/* don't override the environment variable */
if (g_getenv ("GEGL_USE_OPENCL") == NULL && cmd_gegl_opencl)
g_object_set (config, "use-opencl", cmd_gegl_opencl, NULL);
- if (cmd_gegl_queue_limit)
- g_object_set (config, "queue-limit", cmd_gegl_queue_limit, NULL);
+ if (cmd_gegl_queue_size)
+ config->queue_size = atoll (cmd_gegl_queue_size) * 1024 * 1024;
time = gegl_ticks ();
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]