[gegl/swap-backend: 4/4] buffer: merged TileBackendSwap and TileBackendFile
- From: Ville Sokk <villesokk src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl/swap-backend: 4/4] buffer: merged TileBackendSwap and TileBackendFile
- Date: Fri, 15 Feb 2013 19:46:17 +0000 (UTC)
commit 996f0c7ae75a86ecea73674ad911b19c7aa1006f
Author: Ville Sokk <ville sokk gmail com>
Date: Fri Feb 15 21:06:54 2013 +0200
buffer: merged TileBackendSwap and TileBackendFile
gegl/buffer/Makefile.am | 4 +-
gegl/buffer/gegl-buffer.c | 6 +-
gegl/buffer/gegl-tile-backend-file.c | 1430 +++++++++++++++++-----------------
gegl/buffer/gegl-tile-backend-file.h | 54 +-
gegl/buffer/gegl-tile-backend-swap.c | 1003 ------------------------
gegl/buffer/gegl-tile-backend-swap.h | 65 --
gegl/gegl-init.c | 4 +-
7 files changed, 748 insertions(+), 1818 deletions(-)
---
diff --git a/gegl/buffer/Makefile.am b/gegl/buffer/Makefile.am
index 43d9a5d..780468a 100644
--- a/gegl/buffer/Makefile.am
+++ b/gegl/buffer/Makefile.am
@@ -16,7 +16,7 @@ noinst_LTLIBRARIES = libbuffer.la
libbuffer_la_SOURCES = \
gegl-aio-file.c \
gegl-buffer-load.c \
- gegl-tile-backend-swap.c \
+ gegl-tile-backend-file.c \
gegl-buffer-access.c \
gegl-buffer-cl-cache.c \
gegl-buffer-cl-iterator.c \
@@ -50,7 +50,6 @@ libbuffer_la_SOURCES = \
gegl-tile.c \
\
gegl-aio-file.h \
- gegl-tile-backend-swap.h \
gegl-buffer-cl-cache.h \
gegl-buffer-cl-iterator.h \
gegl-buffer-iterator.h \
@@ -83,7 +82,6 @@ libbuffer_la_SOURCES = \
gegl-tile-storage.h \
gegl-tile.h
-libbuffer_la_SOURCES += gegl-tile-backend-file-async.c
#if HAVE_64_BIT
#libbuffer_la_SOURCES += gegl-tile-backend-file-mapped.c
#else
diff --git a/gegl/buffer/gegl-buffer.c b/gegl/buffer/gegl-buffer.c
index 6e160da..ad84873 100644
--- a/gegl/buffer/gegl-buffer.c
+++ b/gegl/buffer/gegl-buffer.c
@@ -47,7 +47,6 @@
#include "gegl-tile-storage.h"
#include "gegl-tile-backend.h"
#include "gegl-tile-backend-file.h"
-#include "gegl-tile-backend-swap.h"
#include "gegl-tile-backend-tiledir.h"
#include "gegl-tile-backend-ram.h"
#include "gegl-tile.h"
@@ -427,8 +426,7 @@ gegl_buffer_dispose (GObject *object)
/* only flush non-internal backends,. */
if (!(GEGL_IS_TILE_BACKEND_FILE (backend) ||
GEGL_IS_TILE_BACKEND_RAM (backend) ||
- GEGL_IS_TILE_BACKEND_TILE_DIR (backend) ||
- GEGL_IS_TILE_BACKEND_SWAP (backend)))
+ GEGL_IS_TILE_BACKEND_TILE_DIR (backend)))
gegl_buffer_flush (buffer);
gegl_tile_source_reinit (GEGL_TILE_SOURCE (handler->source));
@@ -1275,7 +1273,7 @@ gegl_tile_storage_new_cached (gint tile_width, gint tile_height,
GeglTileBackend *backend;
item->ram = FALSE;
- backend = g_object_new (GEGL_TYPE_TILE_BACKEND_SWAP,
+ backend = g_object_new (GEGL_TYPE_TILE_BACKEND_FILE,
"tile-width", tile_width,
"tile-height", tile_height,
"format", babl_fmt,
diff --git a/gegl/buffer/gegl-tile-backend-file.c b/gegl/buffer/gegl-tile-backend-file.c
index 725759a..4cdc435 100644
--- a/gegl/buffer/gegl-tile-backend-file.c
+++ b/gegl/buffer/gegl-tile-backend-file.c
@@ -1,4 +1,4 @@
-/* This file is part of GEGL.
+ /* 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
@@ -14,29 +14,36 @@
* 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 <gio/gio.h>
-#include <sys/types.h>
-#include <sys/stat.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 <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-file.h"
-#include "gegl-buffer-index.h"
-#include "gegl-buffer-types.h"
+#include "gegl-aio-file.h"
#include "gegl-debug.h"
+#include "gegl-config.h"
#ifndef HAVE_FSYNC
@@ -48,386 +55,338 @@
#endif
-struct _GeglTileBackendFile
-{
- GeglTileBackend parent_instance;
+G_DEFINE_TYPE (GeglTileBackendFile, gegl_tile_backend_file, GEGL_TYPE_TILE_BACKEND)
- /* the path to our buffer */
- gchar *path;
+static GObjectClass * parent_class = NULL;
- /* the file exist (and we've thus been able to initialize i and o,
- * the utility call ensure_exist() should be called before any code
- * using i and o)
- */
- gboolean exist;
- /* total size of file */
- guint total;
+typedef struct
+{
+ guint64 offset;
+ gint rev;
+ gint x;
+ gint y;
+ gint z;
+} FileEntry;
+
+typedef struct
+{
+ guint64 start;
+ guint64 end;
+} FileGap;
- /* hashtable containing all entries of buffer, the index is written
- * to the swapfile conforming to the structures laid out in
- * gegl-buffer-index.h
- */
- GHashTable *index;
+enum
+{
+ PROP_0,
+ PROP_PATH
+};
- /* list of offsets to tiles that are free */
- GSList *free_list;
- /* offset to next pre allocated tile slot */
- guint next_pre_alloc;
+void gegl_tile_backend_file_stats (void);
+static void gegl_tile_backend_file_dbg_alloc (gint size);
+static void gegl_tile_backend_file_dbg_dealloc (gint size);
+static inline FileEntry *gegl_tile_backend_file_entry_create (gint x,
+ gint y,
+ gint z);
+static guint64 gegl_tile_backend_file_find_offset (GeglTileBackendFile *self,
+ gint size);
+static inline FileGap * gegl_tile_backend_file_gap_new (guint64 start,
+ guint64 end);
+static void gegl_tile_backend_file_entry_destroy (GeglTileBackendFile *self,
+ FileEntry *entry);
+static inline FileEntry *gegl_tile_backend_file_lookup_entry (GeglTileBackendFile *self,
+ gint x,
+ gint y,
+ gint z);
+static GeglTile * gegl_tile_backend_file_get_tile (GeglTileSource *self,
+ gint x,
+ gint y,
+ gint z);
+static gpointer gegl_tile_backend_file_set_tile (GeglTileSource *self,
+ GeglTile *tile,
+ gint x,
+ gint y,
+ gint z);
+static gpointer gegl_tile_backend_file_void_tile (GeglTileSource *self,
+ GeglTile *tile,
+ gint x,
+ gint y,
+ gint z);
+static GeglBufferHeader gegl_tile_backend_file_read_header (GeglTileBackendFile *self);
+static void gegl_tile_backend_file_write_header (GeglTileBackendFile *self);
+static GList* gegl_tile_backend_file_read_index (GeglTileBackendFile *self);
+static void gegl_tile_backend_file_load_index (GeglTileBackendFile *self);
+static gpointer gegl_tile_backend_file_flush (GeglTileSource *source);
+static gpointer gegl_tile_backend_file_exist_tile (GeglTileSource *self,
+ GeglTile *tile,
+ gint x,
+ gint y,
+ gint z);
+static gpointer gegl_tile_backend_file_command (GeglTileSource *self,
+ GeglTileCommand command,
+ gint x,
+ gint y,
+ gint z,
+ gpointer data);
+static void gegl_tile_backend_file_file_changed (GFileMonitor *monitor,
+ GFile *file,
+ GFile *other_file,
+ GFileMonitorEvent event_type,
+ GeglTileBackendFile *self);
+static guint gegl_tile_backend_file_hashfunc (gconstpointer key);
+static gboolean gegl_tile_backend_file_equalfunc (gconstpointer a,
+ gconstpointer b);
+static GObject * gegl_tile_backend_file_constructor (GType type,
+ guint n_params,
+ GObjectConstructParam *params);
+static void gegl_tile_backend_file_finalize (GObject *object);
+static void gegl_tile_backend_file_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gegl_tile_backend_file_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void gegl_tile_backend_file_class_init (GeglTileBackendFileClass *klass);
+static void gegl_tile_backend_file_init (GeglTileBackendFile *self);
+void gegl_tile_backend_file_cleanup (void);
+
+
+GeglAIOFile *swap_file = NULL;
+GList *swap_gap_list = NULL;
- /* revision of last index sync, for cooperated sharing of a buffer
- * file
- */
- guint32 rev;
- /* a local copy of the header that will be written to the file, in a
- * multiple user per buffer scenario, the flags in the header might
- * be used for locking/signalling
- */
- GeglBufferHeader header;
+/* this debugging is across all buffers */
+static gint allocs = 0;
+static gint file_size = 0;
+static gint peak_allocs = 0;
+static gint peak_file_size = 0;
- gint foffset;
+void
+gegl_tile_backend_file_stats (void)
+{
+ g_warning ("leaked: %i chunks (%f mb) peak: %i (%i bytes %fmb))",
+ allocs, file_size / 1024 / 1024.0,
+ peak_allocs, peak_file_size, peak_file_size / 1024 / 1024.0);
+}
- /* current offset, used when writing the index */
- gint offset;
+static void
+gegl_tile_backend_file_dbg_alloc (gint size)
+{
+ allocs++;
+ file_size += size;
+ if (allocs > peak_allocs)
+ peak_allocs = allocs;
+ if (file_size > peak_file_size)
+ peak_file_size = file_size;
+}
- /* when writing buffer blocks the writer keeps one block unwritten
- * at all times to be able to keep track of the ->next offsets in
- * the blocks.
- */
- GeglBufferBlock *in_holding;
+static void
+gegl_tile_backend_file_dbg_dealloc (gint size)
+{
+ allocs--;
+ file_size -= size;
+}
- /* loading buffer */
- GList *tiles;
+static inline FileEntry *
+gegl_tile_backend_file_entry_create (gint x,
+ gint y,
+ gint z)
+{
+ FileEntry *entry = g_slice_new0 (FileEntry);
- /* GFile refering to our buffer */
- GFile *file;
+ entry->x = x;
+ entry->y = y;
+ entry->z = z;
- GFileMonitor *monitor;
- /* for writing */
- int o;
+ return entry;
+}
- /* for reading */
- int i;
-};
+static guint64
+gegl_tile_backend_file_find_offset (GeglTileBackendFile *self,
+ gint size)
+{
+ FileGap *gap;
+ guint64 offset;
+ if (*self->gap_list)
+ {
+ GList *link = *self->gap_list;
-static void gegl_tile_backend_file_ensure_exist (GeglTileBackendFile *self);
-static gboolean gegl_tile_backend_file_write_block (GeglTileBackendFile *self,
- GeglBufferBlock *block);
-static void gegl_tile_backend_file_dbg_alloc (int size);
-static void gegl_tile_backend_file_dbg_dealloc (int size);
+ while (link)
+ {
+ gap = link->data;
+ if ((gap->end - gap->start) >= size)
+ {
+ guint64 offset = gap->start;
-static inline void
-gegl_tile_backend_file_file_entry_read (GeglTileBackendFile *self,
- GeglBufferTile *entry,
- guchar *dest)
-{
- gint to_be_read;
- gboolean success;
- gint tile_size = gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self));
- goffset offset = entry->offset;
- guchar *tdest = dest;
+ gap->start += size;
- gegl_tile_backend_file_ensure_exist (self);
+ if (gap->start == gap->end)
+ {
+ g_slice_free (FileGap, gap);
+ *self->gap_list = g_list_remove_link (*self->gap_list, link);
+ g_list_free (link);
+ }
- if (self->foffset != offset)
- {
- success = (lseek (self->i, offset, SEEK_SET) >= 0);
+ return offset;
+ }
- if (success == FALSE)
- {
- g_warning ("unable to seek to tile in buffer: %s", g_strerror (errno));
- return;
+ link = link->next;
}
- self->foffset = offset;
}
- to_be_read = tile_size;
- while (to_be_read > 0)
- {
- GError *error = NULL;
- gint byte_read;
+ offset = self->file->total;
- byte_read = read (self->i, tdest + tile_size - to_be_read, to_be_read);
- if (byte_read <= 0)
- {
- g_message ("unable to read tile data from self: "
- "%s (%d/%d bytes read) %s",
- g_strerror (errno), byte_read, to_be_read, error?error->message:"--");
- return;
- }
- to_be_read -= byte_read;
- self->foffset += byte_read;
- }
+ gegl_aio_file_resize (self->file, self->file->total + size + 32 * 4 * 4 * 128 * 64);
- GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "read entry %i,%i,%i at %i", entry->x, entry->y, entry->z,
(gint)offset);
+ GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "pushed resize to %i", (gint)self->file->total);
+
+ return offset;
}
-static inline void
-gegl_tile_backend_file_file_entry_write (GeglTileBackendFile *self,
- GeglBufferTile *entry,
- guchar *source)
+static inline FileGap *
+gegl_tile_backend_file_gap_new (guint64 start,
+ guint64 end)
{
- gint to_be_written;
- gboolean success;
- goffset offset = entry->offset;
- gint tile_size;
-
- gegl_tile_backend_file_ensure_exist (self);
+ FileGap *gap = g_slice_new (FileGap);
- if (self->foffset != offset)
- {
- success = (lseek (self->o, offset, SEEK_SET) >= 0);
- if (success == FALSE)
- {
- g_warning ("unable to seek to tile in buffer: %s", g_strerror (errno));
- return;
- }
- self->foffset = offset;
- }
+ gap->start = start;
+ gap->end = end;
- tile_size = gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self));
-
- to_be_written = tile_size;
-
- while (to_be_written > 0)
- {
- gint wrote;
- wrote = write (self->o,
- source + tile_size - 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);
- return;
- }
- to_be_written -= wrote;
- self->foffset += wrote;
- }
- GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "wrote entry %i,%i,%i at %i", entry->x, entry->y, entry->z,
(gint)offset);
+ return gap;
}
-static inline GeglBufferTile *
-gegl_tile_backend_file_file_entry_new (GeglTileBackendFile *self)
+static void
+gegl_tile_backend_file_entry_destroy (GeglTileBackendFile *self,
+ FileEntry *entry)
{
- GeglBufferTile *entry = gegl_tile_entry_new (0,0,0);
-
- GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "Creating new entry");
+ guint64 start, end;
+ gint tile_size = gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self));
+ GList *link, *link2;
+ FileGap *gap, *gap2;
- gegl_tile_backend_file_ensure_exist (self);
+ start = entry->offset;
+ end = start + tile_size;
- if (self->free_list)
- {
- /* XXX: losing precision ?
- * the free list seems to operate with fixed size datums and
- * only keep track of offsets.
- */
- gint offset = GPOINTER_TO_INT (self->free_list->data);
- entry->offset = offset;
- self->free_list = g_slist_remove (self->free_list, self->free_list->data);
-
- GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, " set offset %i from free list", ((gint)entry->offset));
- }
- else
+ link = *self->gap_list;
+ while (link)
{
- gint tile_size = gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self));
-
- entry->offset = self->next_pre_alloc;
- GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, " set offset %i (next allocation)", (gint)entry->offset);
- self->next_pre_alloc += tile_size;
+ gap = link->data;
- if (self->next_pre_alloc >= self->total) /* automatic growing ensuring that
- we have room for next allocation..
- */
+ if (end == gap->start)
{
- self->total = self->total + 32 * tile_size;
+ gap->start = start;
- GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "growing file to %i bytes", (gint)self->total);
+ if (link->prev)
+ {
+ gap2 = link->prev->data;
- ftruncate (self->o, self->total);
- self->foffset = -1;
+ if (gap->start == gap2->end)
+ {
+ gap2->end = gap->end;
+ g_slice_free (FileGap, gap);
+ *self->gap_list = g_list_remove_link (*self->gap_list, link);
+ g_list_free (link);
+ }
+ }
+ break;
}
- }
- gegl_tile_backend_file_dbg_alloc (gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self)));
- return entry;
-}
-
-static inline void
-gegl_tile_backend_file_file_entry_destroy (GeglBufferTile *entry,
- GeglTileBackendFile *self)
-{
- /* XXX: EEEk, throwing away bits */
- guint offset = entry->offset;
- self->free_list = g_slist_prepend (self->free_list,
- GUINT_TO_POINTER (offset));
- g_hash_table_remove (self->index, entry);
-
- gegl_tile_backend_file_dbg_dealloc (gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self)));
- g_free (entry);
-}
+ else if (start == gap->end)
+ {
+ gap->end = end;
-static gboolean
-gegl_tile_backend_file_write_header (GeglTileBackendFile *self)
-{
- gboolean success;
+ if (link->next)
+ {
+ gap2 = link->next->data;
- gegl_tile_backend_file_ensure_exist (self);
+ if (gap->end == gap2->start)
+ {
+ gap2->start = gap->start;
+ g_slice_free (FileGap, gap);
+ *self->gap_list =
+ g_list_remove_link (*self->gap_list, link);
+ g_list_free (link);
+ }
+ }
+ break;
+ }
+ else if (end < gap->start)
+ {
+ gap = gegl_tile_backend_file_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 == *self->gap_list)
+ *self->gap_list = link2;
+ break;
+ }
+ else if (!link->next)
+ {
+ gap = gegl_tile_backend_file_gap_new (start, end);
+ link->next = g_list_alloc ();
+ link->next->data = gap;
+ link->next->prev = link;
+ break;
+ }
- success = (lseek (self->o, 0, SEEK_SET) != -1);
- if (success == FALSE)
- {
- g_warning ("unable to seek in buffer");
- return FALSE;
+ link = link->next;
}
- write (self->o, &(self->header), 256);
- self->foffset = 256;
- GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "Wrote header, next=%i", (gint)self->header.next);
- return TRUE;
-}
-static gboolean
-gegl_tile_backend_file_write_block (GeglTileBackendFile *self,
- GeglBufferBlock *block)
-{
- gegl_tile_backend_file_ensure_exist (self);
- if (self->in_holding)
+ if (!*self->gap_list)
{
- guint64 next_allocation = self->offset + self->in_holding->length;
+ gap = gegl_tile_backend_file_gap_new (start, end);
+ *self->gap_list = g_list_append (*self->gap_list, gap);
+ }
+ link = g_list_last (*self->gap_list);
+ gap = link->data;
- /* update the next offset pointer in the previous block */
- if (block == NULL)
- /* the previous block was the last block */
- self->in_holding->next = 0;
- else
- self->in_holding->next = next_allocation;
-
- if (self->foffset != self->offset)
- {
- if(lseek (self->o, self->offset, G_SEEK_SET) == -1)
- goto fail;
-
- self->foffset = self->offset;
- }
-
- /* XXX: should promiscuosuly try to compress here as well,. if revisions
- are not matching..
- */
-
- GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "Wrote block: length:%i flags:%i next:%i at offset %i",
- self->in_holding->length,
- self->in_holding->flags,
- (gint)self->in_holding->next,
- (gint)self->offset);
- {
- ssize_t written = write (self->o, self->in_holding,
- self->in_holding->length);
- if(written != -1)
- {
- self->offset += written;
- self->foffset += written;
- }
- }
-
- g_assert (next_allocation == self->offset); /* true as long as
- the simple allocation
- scheme is used */
-
- self->offset = next_allocation;
- }
- else
+ if (gap->end == self->file->total)
{
- /* we're setting up for the first write */
-
- self->offset = self->next_pre_alloc; /* start writing header at end
- * of file, worry about writing
- * header inside free list later
- */
- if (self->foffset != self->offset)
- {
- if(lseek (self->o, self->offset, G_SEEK_SET) == -1)
- goto fail;
-
- self->foffset = self->offset;
- }
+ gegl_aio_file_resize (self->file, gap->start);
+ g_slice_free (FileGap, gap);
+ *self->gap_list = g_list_remove_link (*self->gap_list, link);
+ g_list_free (link);
}
- self->in_holding = block;
-
- return TRUE;
-fail:
- g_warning ("gegl buffer index writing problems for %s",
- self->path);
- return FALSE;
-}
-
-G_DEFINE_TYPE (GeglTileBackendFile, gegl_tile_backend_file, GEGL_TYPE_TILE_BACKEND)
-static GObjectClass * parent_class = NULL;
-
-/* this debugging is across all buffers */
-
-static gint allocs = 0;
-static gint file_size = 0;
-static gint peak_allocs = 0;
-static gint peak_file_size = 0;
-
-void
-gegl_tile_backend_file_stats (void)
-{
- g_warning ("leaked: %i chunks (%f mb) peak: %i (%i bytes %fmb))",
- allocs, file_size / 1024 / 1024.0,
- peak_allocs, peak_file_size, peak_file_size / 1024 / 1024.0);
-}
-
-static void
-gegl_tile_backend_file_dbg_alloc (gint size)
-{
- allocs++;
- file_size += size;
- if (allocs > peak_allocs)
- peak_allocs = allocs;
- if (file_size > peak_file_size)
- peak_file_size = file_size;
-}
-static void
-gegl_tile_backend_file_dbg_dealloc (gint size)
-{
- allocs--;
- file_size -= size;
+ g_hash_table_remove (self->index, entry);
+ g_slice_free (FileEntry, entry);
+ gegl_tile_backend_file_dbg_dealloc (gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self)));
}
-static inline GeglBufferTile *
+static inline FileEntry *
gegl_tile_backend_file_lookup_entry (GeglTileBackendFile *self,
- gint x,
- gint y,
- gint z)
+ gint x,
+ gint y,
+ gint z)
{
- GeglBufferTile *ret;
- GeglBufferTile *key = gegl_tile_entry_new (x,y,z);
+ FileEntry *ret = NULL;
+ FileEntry *key = gegl_tile_backend_file_entry_create (x, y, z);
+
ret = g_hash_table_lookup (self->index, key);
- gegl_tile_entry_destroy (key);
+ g_slice_free (FileEntry, key);
+
return ret;
}
-/* this is the only place that actually should
- * instantiate tiles, when the cache is large enough
- * that should make sure we don't hit this function
- * too often.
- */
static GeglTile *
gegl_tile_backend_file_get_tile (GeglTileSource *self,
- gint x,
- gint y,
- gint z)
+ gint x,
+ gint y,
+ gint z)
{
GeglTileBackend *backend;
GeglTileBackendFile *tile_backend_file;
- GeglBufferTile *entry;
+ FileEntry *entry;
GeglTile *tile = NULL;
gint tile_size;
@@ -443,7 +402,11 @@ gegl_tile_backend_file_get_tile (GeglTileSource *self,
gegl_tile_set_rev (tile, entry->rev);
gegl_tile_mark_as_stored (tile);
- gegl_tile_backend_file_file_entry_read (tile_backend_file, entry, gegl_tile_get_data (tile));
+ gegl_aio_file_read (tile_backend_file->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;
}
@@ -456,24 +419,30 @@ gegl_tile_backend_file_set_tile (GeglTileSource *self,
{
GeglTileBackend *backend;
GeglTileBackendFile *tile_backend_file;
- GeglBufferTile *entry;
+ FileEntry *entry;
+ gint tile_size;
backend = GEGL_TILE_BACKEND (self);
tile_backend_file = GEGL_TILE_BACKEND_FILE (backend);
+ tile_size = gegl_tile_backend_get_tile_size (backend);
entry = gegl_tile_backend_file_lookup_entry (tile_backend_file, x, y, z);
if (entry == NULL)
{
- entry = gegl_tile_backend_file_file_entry_new (tile_backend_file);
- entry->x = x;
- entry->y = y;
- entry->z = z;
+ entry = gegl_tile_backend_file_entry_create (x, y, z);
+ entry->offset = gegl_tile_backend_file_find_offset (tile_backend_file, tile_size);
g_hash_table_insert (tile_backend_file->index, entry, entry);
+ gegl_tile_backend_file_dbg_alloc (tile_size);
}
- entry->rev = gegl_tile_get_rev (tile);
- gegl_tile_backend_file_file_entry_write (tile_backend_file, entry, gegl_tile_get_data (tile));
+ gegl_aio_file_write (tile_backend_file->file, entry->offset,
+ tile_size,
+ 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;
}
@@ -486,7 +455,7 @@ gegl_tile_backend_file_void_tile (GeglTileSource *self,
{
GeglTileBackend *backend;
GeglTileBackendFile *tile_backend_file;
- GeglBufferTile *entry;
+ FileEntry *entry;
backend = GEGL_TILE_BACKEND (self);
tile_backend_file = GEGL_TILE_BACKEND_FILE (backend);
@@ -494,87 +463,270 @@ gegl_tile_backend_file_void_tile (GeglTileSource *self,
if (entry != NULL)
{
- gegl_tile_backend_file_file_entry_destroy (entry, tile_backend_file);
+ GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "void tile %i, %i, %i", x, y, z);
+
+ gegl_tile_backend_file_entry_destroy (tile_backend_file, entry);
}
return NULL;
}
-static gpointer
-gegl_tile_backend_file_exist_tile (GeglTileSource *self,
- GeglTile *tile,
- gint x,
- gint y,
- gint z)
+static GeglBufferHeader
+gegl_tile_backend_file_read_header (GeglTileBackendFile *self)
{
- GeglTileBackend *backend;
- GeglTileBackendFile *tile_backend_file;
- GeglBufferTile *entry;
+ GeglBufferHeader ret;
- backend = GEGL_TILE_BACKEND (self);
- tile_backend_file = GEGL_TILE_BACKEND_FILE (backend);
- entry = gegl_tile_backend_file_lookup_entry (tile_backend_file, x, y, z);
+ gegl_aio_file_read(self->file, 0, sizeof (GeglBufferHeader), (guchar*)&ret);
- return entry!=NULL?((gpointer)0x1):NULL;
+ 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_file_write_header (GeglTileBackendFile *self)
+{
+ gegl_aio_file_write (self->file, 0, sizeof (GeglBufferHeader), (guchar*)&self->header);
+}
-static gpointer
-gegl_tile_backend_file_flush (GeglTileSource *source,
- GeglTile *tile,
- gint x,
- gint y,
- gint z)
+static GList *
+gegl_tile_backend_file_read_index (GeglTileBackendFile *self)
{
- GeglTileBackend *backend;
- GeglTileBackendFile *self;
- GList *tiles;
+ GList *ret = NULL;
+ guint64 offset = self->header.next;
+ GeglBufferTile *item;
- backend = GEGL_TILE_BACKEND (source);
- self = GEGL_TILE_BACKEND_FILE (backend);
+ 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);
+ }
- gegl_tile_backend_file_ensure_exist (self);
+ ret = g_list_reverse (ret);
- GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "flushing %s", self->path);
+ return ret;
+}
+static void
+gegl_tile_backend_file_load_index (GeglTileBackendFile *self)
+{
+ GeglBufferHeader new_header;
+ GList *tiles, *iter;
+ GeglTileBackend *backend = GEGL_TILE_BACKEND (self);
+ guint64 max = 0;
+ gint tile_size;
- self->header.rev ++;
- self->header.next = self->next_pre_alloc; /* this is the offset
- we start handing
- out headers from*/
- tiles = g_hash_table_get_keys (self->index);
+ new_header = gegl_tile_backend_file_read_header (self);
- if (tiles == NULL)
- self->header.next = 0;
- else
+ while (new_header.flags & GEGL_FLAG_LOCKED)
{
- GList *iter;
- for (iter = tiles; iter; iter = iter->next)
- {
- GeglBufferItem *item = iter->data;
+ g_usleep (50000);
+ new_header = gegl_tile_backend_file_read_header (self);
+ }
- gegl_tile_backend_file_write_block (self, &item->block);
- }
- gegl_tile_backend_file_write_block (self, NULL); /* terminate the index */
- g_list_free (tiles);
+ 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);
}
- gegl_tile_backend_file_write_header (self);
- fsync (self->o);
+ tile_size = gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self));
+ tiles = gegl_tile_backend_file_read_index (self);
- GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "flushed %s", self->path);
+ for (iter = tiles; iter; iter = iter->next)
+ {
+ GeglBufferTile *item = iter->data;
+ FileEntry *new, *existing =
+ gegl_tile_backend_file_lookup_entry (self, item->x, item->y, item->z);
- return (gpointer)0xf0f;
-}
+ if (item->offset > max)
+ max = item->offset + tile_size;
-enum
-{
- PROP_0,
- PROP_PATH
-};
+ 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;
-static gpointer
-gegl_tile_backend_file_command (GeglTileSource *self,
+ 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_file_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_file_flush (GeglTileSource *source)
+{
+ GeglTileBackend *backend;
+ GeglTileBackendFile *self;
+ GList *tiles;
+
+ backend = GEGL_TILE_BACKEND (source);
+ self = GEGL_TILE_BACKEND_FILE (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_file_find_offset (self, index_len);
+ index_len = 0;
+
+ for (iter = tiles; iter; iter = iter->next)
+ {
+ FileEntry *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_file_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_file_exist_tile (GeglTileSource *self,
+ GeglTile *tile,
+ gint x,
+ gint y,
+ gint z)
+{
+ GeglTileBackend *backend;
+ GeglTileBackendFile *tile_backend_file;
+ FileEntry *entry;
+
+ backend = GEGL_TILE_BACKEND (self);
+ tile_backend_file = GEGL_TILE_BACKEND_FILE (backend);
+ entry = gegl_tile_backend_file_lookup_entry (tile_backend_file, x, y, z);
+
+ return entry!=NULL?((gpointer)0x1):NULL;
+}
+
+gboolean
+gegl_tile_backend_file_try_lock (GeglTileBackendFile *self)
+{
+ GeglBufferHeader new_header = gegl_tile_backend_file_read_header (self);
+
+ if (new_header.flags & GEGL_FLAG_LOCKED)
+ return FALSE;
+
+ self->header.flags += GEGL_FLAG_LOCKED;
+ gegl_tile_backend_file_write_header (self);
+ gegl_aio_file_sync (self->file);
+
+ return TRUE;
+}
+
+gboolean
+gegl_tile_backend_file_unlock (GeglTileBackendFile *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_file_write_header (self);
+ gegl_aio_file_sync (self->file);
+
+ return TRUE;
+}
+
+static gpointer
+gegl_tile_backend_file_command (GeglTileSource *self,
GeglTileCommand command,
gint x,
gint y,
@@ -587,20 +739,14 @@ gegl_tile_backend_file_command (GeglTileSource *self,
return gegl_tile_backend_file_get_tile (self, x, y, z);
case GEGL_TILE_SET:
return gegl_tile_backend_file_set_tile (self, data, x, y, z);
-
case GEGL_TILE_IDLE:
- return NULL; /* we could perhaps lazily be writing indexes
- * at some intervals, making it work as an
- * autosave for the buffer?
- */
-
+ return NULL;
case GEGL_TILE_VOID:
return gegl_tile_backend_file_void_tile (self, data, x, y, z);
-
case GEGL_TILE_EXIST:
return gegl_tile_backend_file_exist_tile (self, data, x, y, z);
case GEGL_TILE_FLUSH:
- return gegl_tile_backend_file_flush (self, data, x, y, z);
+ return gegl_tile_backend_file_flush (self);
default:
g_assert (command < GEGL_TILE_LAST_COMMAND &&
@@ -610,95 +756,25 @@ gegl_tile_backend_file_command (GeglTileSource *self,
}
static void
-gegl_tile_backend_file_set_property (GObject *object,
- guint property_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- GeglTileBackendFile *self = GEGL_TILE_BACKEND_FILE (object);
-
- switch (property_id)
- {
- case PROP_PATH:
- if (self->path)
- g_free (self->path);
- self->path = g_value_dup_string (value);
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
- break;
- }
-}
-
-static void
-gegl_tile_backend_file_get_property (GObject *object,
- guint property_id,
- GValue *value,
- GParamSpec *pspec)
+gegl_tile_backend_file_file_changed (GFileMonitor *monitor,
+ GFile *file,
+ GFile *other_file,
+ GFileMonitorEvent event_type,
+ GeglTileBackendFile *self)
{
- GeglTileBackendFile *self = GEGL_TILE_BACKEND_FILE (object);
-
- 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_file_finalize (GObject *object)
-{
- GeglTileBackendFile *self = (GeglTileBackendFile *) object;
-
- if (self->index)
- g_hash_table_unref (self->index);
-
- if (self->exist)
- {
- GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "finalizing buffer %s", self->path);
-
- if (self->i != -1)
- {
- close (self->i);
- self->i = -1;
- }
- if (self->o != -1)
- {
- close (self->o);
- self->o = -1;
- }
- }
-
- if (self->path)
- {
- gegl_tile_backend_unlink_swap (self->path);
- g_free (self->path);
- }
-
- if (self->monitor)
- g_object_unref (self->monitor);
-
- if (self->file)
- g_object_unref (self->file);
-
- (*G_OBJECT_CLASS (parent_class)->finalize)(object);
+ if (event_type == G_FILE_MONITOR_EVENT_CHANGED)
+ gegl_tile_backend_file_load_index (self);
}
static guint
gegl_tile_backend_file_hashfunc (gconstpointer key)
{
- const GeglBufferTile *e = key;
+ const FileEntry *entry = key;
guint hash;
gint i;
- gint srcA = e->x;
- gint srcB = e->y;
- gint srcC = e->z;
+ gint srcA = entry->x;
+ gint srcB = entry->y;
+ gint srcC = entry->z;
/* interleave the 10 least significant bits of all coordinates,
* this gives us Z-order / morton order of the space and should
@@ -718,10 +794,10 @@ gegl_tile_backend_file_hashfunc (gconstpointer key)
static gboolean
gegl_tile_backend_file_equalfunc (gconstpointer a,
- gconstpointer b)
+ gconstpointer b)
{
- const GeglBufferTile *ea = a;
- const GeglBufferTile *eb = b;
+ const FileEntry *ea = a;
+ const FileEntry *eb = b;
if (ea->x == eb->x &&
ea->y == eb->y &&
@@ -731,260 +807,217 @@ gegl_tile_backend_file_equalfunc (gconstpointer a,
return FALSE;
}
-
-static void
-gegl_tile_backend_file_load_index (GeglTileBackendFile *self,
- gboolean block)
+static GObject *
+gegl_tile_backend_file_constructor (GType type,
+ guint n_params,
+ GObjectConstructParam *params)
{
- GeglBufferHeader new_header;
- GList *iter;
- GeglTileBackend *backend;
- goffset offset = 0;
- goffset max=0;
- gint tile_size;
-
- /* compute total from and next pre alloc by monitoring tiles as they
- * are added here
- */
- /* reload header */
- new_header = gegl_buffer_read_header (self->i, &offset, NULL)->header;
- self->foffset = 256;
+ GObject *object;
+ GeglTileBackendFile *self;
+ GeglTileBackend *backend;
- while (new_header.flags & GEGL_FLAG_LOCKED)
- {
- g_usleep (50000);
- new_header = gegl_buffer_read_header (self->i, &offset, NULL)->header;
- self->foffset = 256;
- }
+ object = G_OBJECT_CLASS (parent_class)->constructor (type, n_params, params);
+ self = GEGL_TILE_BACKEND_FILE (object);
+ backend = GEGL_TILE_BACKEND (self);
- if (new_header.rev == self->header.rev)
- {
- GEGL_NOTE(GEGL_DEBUG_TILE_BACKEND, "header not changed: %s", self->path);
- return;
- }
- else
+ self->index = g_hash_table_new (gegl_tile_backend_file_hashfunc,
+ gegl_tile_backend_file_equalfunc);
+
+ if (self->path)
{
- self->header=new_header;
- GEGL_NOTE(GEGL_DEBUG_TILE_BACKEND, "loading index: %s", self->path);
- }
+ /* if the path is specified, use a separate file for this buffer */
- 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->foffset = -1;
- 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;
- for (iter = self->tiles; iter; iter=iter->next)
+ 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_file_file_changed),
+ self);
+ self->header = gegl_tile_backend_file_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_file_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
{
- GeglBufferItem *item = iter->data;
+ /* use a file that's shared between multiple buffers */
+ if (swap_file == NULL)
+ {
+ gchar *filename, *path;
- GeglBufferItem *existing = g_hash_table_lookup (self->index, item);
+ 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);
+ }
- if (item->tile.offset > max)
- max = item->tile.offset + tile_size;
+ self->gap_list = &swap_gap_list;
+ self->file = swap_file;
- if (existing)
- {
- if (existing->tile.rev == item->tile.rev)
- {
- g_assert (existing->tile.offset == item->tile.offset);
- existing->tile = item->tile;
- g_free (item);
- continue;
- }
- else
- {
- GeglTileStorage *storage =
- (void*)gegl_tile_backend_peek_storage (backend);
- GeglRectangle rect;
- g_hash_table_remove (self->index, existing);
+ gegl_buffer_header_init (&self->header,
+ backend->priv->tile_width,
+ backend->priv->tile_height,
+ backend->priv->px_size,
+ backend->priv->format);
+ }
- gegl_tile_source_refetch (GEGL_TILE_SOURCE (storage),
- existing->tile.x,
- existing->tile.y,
- existing->tile.z);
+ backend->priv->header = &self->header;
- if (existing->tile.z == 0)
- {
- rect.width = self->header.tile_width;
- rect.height = self->header.tile_height;
- rect.x = existing->tile.x * self->header.tile_width;
- rect.y = existing->tile.y * self->header.tile_height;
- }
- g_free (existing);
+ GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "constructing file backend");
- g_signal_emit_by_name (storage, "changed", &rect, NULL);
- }
- }
- g_hash_table_insert (self->index, iter->data, iter->data);
- }
- g_list_free (self->tiles);
- g_slist_free (self->free_list);
- self->free_list = NULL;
- self->next_pre_alloc = max; /* if bigger than own? */
- self->total = max;
- self->tiles = NULL;
+ return object;
}
static void
-gegl_tile_backend_file_file_changed (GFileMonitor *monitor,
- GFile *file,
- GFile *other_file,
- GFileMonitorEvent event_type,
- GeglTileBackendFile *self)
+gegl_tile_backend_file_finalize (GObject *object)
{
- if (event_type == G_FILE_MONITOR_EVENT_CHANGED /*G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT*/ )
+ GeglTileBackendFile *self = GEGL_TILE_BACKEND_FILE (object);
+
+ if (self->index)
{
- gegl_tile_backend_file_load_index (self, TRUE);
- self->foffset = -1;
- }
-}
+ GList *tiles = g_hash_table_get_keys (self->index);
-static GObject *
-gegl_tile_backend_file_constructor (GType type,
- guint n_params,
- GObjectConstructParam *params)
-{
- GObject *object;
- GeglTileBackendFile *self;
- GeglTileBackend *backend;
+ if (tiles != NULL)
+ {
+ GList *iter;
- object = G_OBJECT_CLASS (parent_class)->constructor (type, n_params, params);
- self = GEGL_TILE_BACKEND_FILE (object);
- backend = GEGL_TILE_BACKEND (object);
+ for (iter = tiles; iter; iter = iter->next)
+ gegl_tile_backend_file_entry_destroy (self, iter->data);
+ }
- GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "constructing file backend: %s", self->path);
+ g_list_free (tiles);
- self->file = g_file_new_for_commandline_arg (self->path);
- self->i = self->o = -1;
- self->index = g_hash_table_new (gegl_tile_backend_file_hashfunc, gegl_tile_backend_file_equalfunc);
+ g_hash_table_unref (self->index);
+ self->index = NULL;
+ }
- /* If the file already exists open it, assuming it is a GeglBuffer. */
- if (g_access (self->path, F_OK) != -1)
+ if (self->file && self->file != swap_file)
{
- goffset offset = 0;
-
- /* Install a monitor for changes to the file in case other applications
- * might be writing to the buffer
- */
- self->monitor = g_file_monitor_file (self->file, G_FILE_MONITOR_NONE,
- NULL, NULL);
- g_signal_connect (self->monitor, "changed",
- G_CALLBACK (gegl_tile_backend_file_file_changed),
- self);
-
- self->o = g_open (self->path, O_RDWR|O_CREAT, 0770);
- if (self->o == -1)
- {
- /* Try again but this time with only read access. This is
- * a quick-fix for make distcheck, where img_cmp fails
- * when it opens a GeglBuffer file in the source tree
- * (which is read-only).
- */
- self->o = g_open (self->path, O_RDONLY, 0770);
+ g_object_unref (self->file);
+ self->file = NULL;
+ }
- if (self->o == -1)
- g_warning ("%s: Could not open '%s': %s", G_STRFUNC, self->path, g_strerror (errno));
- }
- self->i = dup (self->o);
-
- self->header = gegl_buffer_read_header (self->i, &offset, NULL)->header;
- self->header.rev = 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;
-
- /* insert each of the entries into the hash table */
- gegl_tile_backend_file_load_index (self, TRUE);
- self->exist = TRUE;
- g_assert (self->i != -1);
- g_assert (self->o != -1);
-
- /* to autoflush gegl_buffer_set */
-
- /* XXX: poking at internals, icky */
- backend->priv->shared = TRUE;
+ if (self->gfile)
+ {
+ g_object_unref (self->gfile);
+ self->gfile = NULL;
}
- else
+
+ if (self->monitor)
+ {
+ g_object_unref (self->monitor);
+ self->monitor = NULL;
+ }
+
+ if (self->path)
{
- self->exist = FALSE; /* this is also the default, the file will be created on demand */
+ g_free (self->path);
+ self->path = NULL;
}
- g_assert (self->file);
+ if (*self->gap_list && *self->gap_list != swap_gap_list)
+ {
+ GList *iter;
- backend->priv->header = &self->header;
+ for (iter = *self->gap_list; iter; iter = iter->next)
+ g_slice_free (FileGap, iter->data);
- return object;
+ g_list_free (*self->gap_list);
+ *self->gap_list = NULL;
+ }
+
+ (*G_OBJECT_CLASS (parent_class)->finalize)(object);
}
static void
-gegl_tile_backend_file_ensure_exist (GeglTileBackendFile *self)
+gegl_tile_backend_file_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
{
- if (!self->exist)
- {
- GeglTileBackend *backend;
- self->exist = TRUE;
-
- backend = GEGL_TILE_BACKEND (self);
+ GeglTileBackendFile *self = GEGL_TILE_BACKEND_FILE (object);
- GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "creating swapfile %s", self->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;
+ }
+}
- self->o = g_open (self->path, O_RDWR|O_CREAT, 0770);
- if (self->o == -1)
- g_warning ("%s: Could not open '%s': %s", G_STRFUNC, self->path, g_strerror (errno));
+static void
+gegl_tile_backend_file_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GeglTileBackendFile *self = GEGL_TILE_BACKEND_FILE (object);
- self->next_pre_alloc = 256; /* reserved space for header */
- self->total = 256; /* reserved space for header */
- self->foffset = 0;
- gegl_buffer_header_init (&self->header,
- backend->priv->tile_width,
- backend->priv->tile_height,
- backend->priv->px_size,
- backend->priv->format
- );
- gegl_tile_backend_file_write_header (self);
- self->foffset = 256;
- fsync (self->o);
- self->i = dup (self->o);
-
- /*self->i = G_INPUT_STREAM (g_file_read (self->file, NULL, NULL));*/
- self->next_pre_alloc = 256; /* reserved space for header */
- self->total = 256; /* reserved space for header */
- g_assert (self->i != -1);
- g_assert (self->o != -1);
+ 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_file_class_init (GeglTileBackendFileClass *klass)
{
- GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
parent_class = g_type_class_peek_parent (klass);
- gobject_class->get_property = gegl_tile_backend_file_get_property;
- gobject_class->set_property = gegl_tile_backend_file_set_property;
gobject_class->constructor = gegl_tile_backend_file_constructor;
gobject_class->finalize = gegl_tile_backend_file_finalize;
-
-
- GEGL_BUFFER_STRUCT_CHECK_PADDING;
+ gobject_class->set_property = gegl_tile_backend_file_set_property;
+ gobject_class->get_property = gegl_tile_backend_file_get_property;
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",
+ "Path of the backing file",
NULL,
- G_PARAM_CONSTRUCT |
+ G_PARAM_CONSTRUCT_ONLY |
G_PARAM_READWRITE));
}
@@ -992,41 +1025,28 @@ static void
gegl_tile_backend_file_init (GeglTileBackendFile *self)
{
((GeglTileSource*)self)->command = gegl_tile_backend_file_command;
- self->path = NULL;
- self->file = NULL;
- self->i = -1;
- self->o = -1;
- self->index = NULL;
- self->free_list = NULL;
- self->next_pre_alloc = 256; /* reserved space for header */
- self->total = 256; /* reserved space for header */
-}
-gboolean
-gegl_tile_backend_file_try_lock (GeglTileBackendFile *self)
-{
- GeglBufferHeader new_header;
- new_header = gegl_buffer_read_header (self->i, NULL, NULL)->header;
- if (new_header.flags & GEGL_FLAG_LOCKED)
- {
- return FALSE;
- }
- self->header.flags += GEGL_FLAG_LOCKED;
- gegl_tile_backend_file_write_header (self);
- fsync (self->o);
- return TRUE;
+ self->path = NULL;
+ self->file = NULL;
+ self->index = NULL;
+ self->gap_list = NULL;
+ self->gfile = NULL;
+ self->monitor = NULL;
}
-gboolean
-gegl_tile_backend_file_unlock (GeglTileBackendFile *self)
+void
+gegl_tile_backend_file_cleanup (void)
{
- if (!(self->header.flags & GEGL_FLAG_LOCKED))
+ if (swap_file)
+ g_object_unref (swap_file);
+
+ if (swap_gap_list)
{
- g_warning ("tried to unlock unlocked buffer");
- return FALSE;
+ GList *iter;
+
+ for (iter = swap_gap_list; iter; iter = iter->next)
+ g_slice_free (FileGap, iter->data);
+
+ g_list_free (swap_gap_list);
}
- self->header.flags -= GEGL_FLAG_LOCKED;
- gegl_tile_backend_file_write_header (self);
- fsync (self->o);
- return TRUE;
}
diff --git a/gegl/buffer/gegl-tile-backend-file.h b/gegl/buffer/gegl-tile-backend-file.h
index 00ba5fc..c2426ce 100644
--- a/gegl/buffer/gegl-tile-backend-file.h
+++ b/gegl/buffer/gegl-tile-backend-file.h
@@ -13,18 +13,17 @@
* 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 Ãyvind KolÃs <pippin gimp org>
+ * Copyright 2012 Ville Sokk <ville sokk gmail com>
*/
#ifndef __GEGL_TILE_BACKEND_FILE_H__
#define __GEGL_TILE_BACKEND_FILE_H__
+#include <glib.h>
+#include <gio/gio.h>
#include "gegl-tile-backend.h"
#include "gegl-buffer-index.h"
-
-/***
- * GeglTileBackendFile is a GeglTileBackend that store tiles in a unique file.
- */
+#include "gegl-aio-file.h"
G_BEGIN_DECLS
@@ -39,45 +38,28 @@ G_BEGIN_DECLS
typedef struct _GeglTileBackendFile GeglTileBackendFile;
typedef struct _GeglTileBackendFileClass GeglTileBackendFileClass;
-typedef enum
-{
- OP_WRITE,
- OP_WRITE_BLOCK,
- OP_TRUNCATE,
- OP_SYNC
-} GeglFileBackendThreadOp;
-
-typedef struct
-{
- GeglBufferTile *tile;
- /* reference to the writer queue links of this entry when writing
- tile data or a GeglBufferBlock*/
- GList *tile_link;
- GList *block_link;
-} GeglFileBackendEntry;
-
-typedef struct
-{
- gint length; /* length of data if writing tile or
- length of file if truncating */
- guchar *source;
- goffset offset;
- GeglTileBackendFile *file; /* the file we are operating on */
- GeglFileBackendThreadOp operation; /* type of file operation, see above */
- GeglFileBackendEntry *entry;
-} GeglFileBackendThreadParams;
-
struct _GeglTileBackendFileClass
{
GeglTileBackendClass parent_class;
};
+struct _GeglTileBackendFile
+{
+ GeglTileBackend parent_instance;
+ gchar *path;
+ GeglAIOFile *file;
+ GHashTable *index;
+ GList **gap_list;
+ GeglBufferHeader header;
+ GFile *gfile;
+ GFileMonitor *monitor;
+};
+
GType gegl_tile_backend_file_get_type (void) G_GNUC_CONST;
-void gegl_tile_backend_file_stats (void);
+gboolean gegl_tile_backend_file_try_lock (GeglTileBackendFile *self);
-gboolean gegl_tile_backend_file_try_lock (GeglTileBackendFile *file);
-gboolean gegl_tile_backend_file_unlock (GeglTileBackendFile *file);
+gboolean gegl_tile_backend_file_unlock (GeglTileBackendFile *self);
G_END_DECLS
diff --git a/gegl/gegl-init.c b/gegl/gegl-init.c
index 776ef16..9086c66 100644
--- a/gegl/gegl-init.c
+++ b/gegl/gegl-init.c
@@ -356,7 +356,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 gegl_tile_backend_file_cleanup (void);
void
gegl_exit (void)
@@ -371,7 +371,7 @@ gegl_exit (void)
timing = gegl_ticks ();
- gegl_tile_backend_swap_cleanup ();
+ gegl_tile_backend_file_cleanup ();
gegl_aio_file_cleanup ();
gegl_tile_storage_cache_cleanup ();
gegl_tile_cache_destroy ();
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]