|
Packit Service |
2781ba |
/* This file is part of GEGL.
|
|
Packit Service |
2781ba |
*
|
|
Packit Service |
2781ba |
* This library is free software; you can redistribute it and/or
|
|
Packit Service |
2781ba |
* modify it under the terms of the GNU Lesser General Public
|
|
Packit Service |
2781ba |
* License as published by the Free Software Foundation; either
|
|
Packit Service |
2781ba |
* version 3 of the License, or (at your option) any later version.
|
|
Packit Service |
2781ba |
*
|
|
Packit Service |
2781ba |
* This library is distributed in the hope that it will be useful,
|
|
Packit Service |
2781ba |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
2781ba |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit Service |
2781ba |
* Lesser General Public License for more details.
|
|
Packit Service |
2781ba |
*
|
|
Packit Service |
2781ba |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit Service |
2781ba |
* License along with GEGL; if not, see <http://www.gnu.org/licenses/>.
|
|
Packit Service |
2781ba |
*
|
|
Packit Service |
2781ba |
* Copyright 2006, 2007, 2008 Øyvind Kolås <pippin@gimp.org>
|
|
Packit Service |
2781ba |
*/
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
#include "config.h"
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
#include <gio/gio.h>
|
|
Packit Service |
2781ba |
#include <sys/types.h>
|
|
Packit Service |
2781ba |
#include <sys/stat.h>
|
|
Packit Service |
2781ba |
#include <fcntl.h>
|
|
Packit Service |
2781ba |
#include <unistd.h>
|
|
Packit Service |
2781ba |
#include <string.h>
|
|
Packit Service |
2781ba |
#include <errno.h>
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
#include <glib-object.h>
|
|
Packit Service |
2781ba |
#include <glib/gprintf.h>
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
#include "gegl.h"
|
|
Packit Service |
2781ba |
#include "gegl-tile-backend.h"
|
|
Packit Service |
2781ba |
#include "gegl-tile-backend-file.h"
|
|
Packit Service |
2781ba |
#include "gegl-buffer-index.h"
|
|
Packit Service |
2781ba |
#include "gegl-buffer-types.h"
|
|
Packit Service |
2781ba |
#include "gegl-debug.h"
|
|
Packit Service |
2781ba |
//#include "gegl-types-internal.h"
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
#ifndef HAVE_FSYNC
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
#ifdef G_OS_WIN32
|
|
Packit Service |
2781ba |
#define fsync _commit
|
|
Packit Service |
2781ba |
#endif
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
#endif
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
struct _GeglTileBackendFile
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglTileBackend parent_instance;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* the path to our buffer */
|
|
Packit Service |
2781ba |
gchar *path;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* the file exist (and we've thus been able to initialize i and o,
|
|
Packit Service |
2781ba |
* the utility call ensure_exist() should be called before any code
|
|
Packit Service |
2781ba |
* using i and o)
|
|
Packit Service |
2781ba |
*/
|
|
Packit Service |
2781ba |
gboolean exist;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* total size of file */
|
|
Packit Service |
2781ba |
guint total;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* hashtable containing all entries of buffer, the index is written
|
|
Packit Service |
2781ba |
* to the swapfile conforming to the structures laid out in
|
|
Packit Service |
2781ba |
* gegl-buffer-index.h
|
|
Packit Service |
2781ba |
*/
|
|
Packit Service |
2781ba |
GHashTable *index;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* list of offsets to tiles that are free */
|
|
Packit Service |
2781ba |
GSList *free_list;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* offset to next pre allocated tile slot */
|
|
Packit Service |
2781ba |
guint next_pre_alloc;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* revision of last index sync, for cooperated sharing of a buffer
|
|
Packit Service |
2781ba |
* file
|
|
Packit Service |
2781ba |
*/
|
|
Packit Service |
2781ba |
guint32 rev;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* a local copy of the header that will be written to the file, in a
|
|
Packit Service |
2781ba |
* multiple user per buffer scenario, the flags in the header might
|
|
Packit Service |
2781ba |
* be used for locking/signalling
|
|
Packit Service |
2781ba |
*/
|
|
Packit Service |
2781ba |
GeglBufferHeader header;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gint foffset;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* current offset, used when writing the index */
|
|
Packit Service |
2781ba |
gint offset;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* when writing buffer blocks the writer keeps one block unwritten
|
|
Packit Service |
2781ba |
* at all times to be able to keep track of the ->next offsets in
|
|
Packit Service |
2781ba |
* the blocks.
|
|
Packit Service |
2781ba |
*/
|
|
Packit Service |
2781ba |
GeglBufferBlock *in_holding;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* loading buffer */
|
|
Packit Service |
2781ba |
GList *tiles;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* GFile refering to our buffer */
|
|
Packit Service |
2781ba |
GFile *file;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
GFileMonitor *monitor;
|
|
Packit Service |
2781ba |
/* for writing */
|
|
Packit Service |
2781ba |
int o;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* for reading */
|
|
Packit Service |
2781ba |
int i;
|
|
Packit Service |
2781ba |
};
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static void gegl_tile_backend_file_ensure_exist (GeglTileBackendFile *self);
|
|
Packit Service |
2781ba |
static gboolean gegl_tile_backend_file_write_block (GeglTileBackendFile *self,
|
|
Packit Service |
2781ba |
GeglBufferBlock *block);
|
|
Packit Service |
2781ba |
static void gegl_tile_backend_file_dbg_alloc (int size);
|
|
Packit Service |
2781ba |
static void gegl_tile_backend_file_dbg_dealloc (int size);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static inline void
|
|
Packit Service |
2781ba |
gegl_tile_backend_file_file_entry_read (GeglTileBackendFile *self,
|
|
Packit Service |
2781ba |
GeglBufferTile *entry,
|
|
Packit Service |
2781ba |
guchar *dest)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
gint to_be_read;
|
|
Packit Service |
2781ba |
gboolean success;
|
|
Packit Service |
2781ba |
gint tile_size = gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self));
|
|
Packit Service |
2781ba |
goffset offset = entry->offset;
|
|
Packit Service |
2781ba |
guchar *tdest = dest;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gegl_tile_backend_file_ensure_exist (self);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (self->foffset != offset)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
success = (lseek (self->i, offset, SEEK_SET) >= 0);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (success == FALSE)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
g_warning ("unable to seek to tile in buffer: %s", g_strerror (errno));
|
|
Packit Service |
2781ba |
return;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
self->foffset = offset;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
to_be_read = tile_size;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
while (to_be_read > 0)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GError *error = NULL;
|
|
Packit Service |
2781ba |
gint byte_read;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
byte_read = read (self->i, tdest + tile_size - to_be_read, to_be_read);
|
|
Packit Service |
2781ba |
if (byte_read <= 0)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
g_message ("unable to read tile data from self: "
|
|
Packit Service |
2781ba |
"%s (%d/%d bytes read) %s",
|
|
Packit Service |
2781ba |
g_strerror (errno), byte_read, to_be_read, error?error->message:"--");
|
|
Packit Service |
2781ba |
return;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
to_be_read -= byte_read;
|
|
Packit Service |
2781ba |
self->foffset += byte_read;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "read entry %i,%i,%i at %i", entry->x, entry->y, entry->z, (gint)offset);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static inline void
|
|
Packit Service |
2781ba |
gegl_tile_backend_file_file_entry_write (GeglTileBackendFile *self,
|
|
Packit Service |
2781ba |
GeglBufferTile *entry,
|
|
Packit Service |
2781ba |
guchar *source)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
gint to_be_written;
|
|
Packit Service |
2781ba |
gboolean success;
|
|
Packit Service |
2781ba |
goffset offset = entry->offset;
|
|
Packit Service |
2781ba |
gint tile_size;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gegl_tile_backend_file_ensure_exist (self);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (self->foffset != offset)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
success = (lseek (self->o, offset, SEEK_SET) >= 0);
|
|
Packit Service |
2781ba |
if (success == FALSE)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
g_warning ("unable to seek to tile in buffer: %s", g_strerror (errno));
|
|
Packit Service |
2781ba |
return;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
self->foffset = offset;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
tile_size = gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self));
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
to_be_written = tile_size;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
while (to_be_written > 0)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
gint wrote;
|
|
Packit Service |
2781ba |
wrote = write (self->o,
|
|
Packit Service |
2781ba |
source + tile_size - to_be_written,
|
|
Packit Service |
2781ba |
to_be_written);
|
|
Packit Service |
2781ba |
if (wrote <= 0)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
g_message ("unable to write tile data to self: "
|
|
Packit Service |
2781ba |
"%s (%d/%d bytes written)",
|
|
Packit Service |
2781ba |
g_strerror (errno), wrote, to_be_written);
|
|
Packit Service |
2781ba |
return;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
to_be_written -= wrote;
|
|
Packit Service |
2781ba |
self->foffset += wrote;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "wrote entry %i,%i,%i at %i", entry->x, entry->y, entry->z, (gint)offset);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static inline GeglBufferTile *
|
|
Packit Service |
2781ba |
gegl_tile_backend_file_file_entry_new (GeglTileBackendFile *self)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglBufferTile *entry = gegl_tile_entry_new (0,0,0);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "Creating new entry");
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gegl_tile_backend_file_ensure_exist (self);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (self->free_list)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
/* XXX: losing precision ?
|
|
Packit Service |
2781ba |
* the free list seems to operate with fixed size datums and
|
|
Packit Service |
2781ba |
* only keep track of offsets.
|
|
Packit Service |
2781ba |
*/
|
|
Packit Service |
2781ba |
gint offset = GPOINTER_TO_INT (self->free_list->data);
|
|
Packit Service |
2781ba |
entry->offset = offset;
|
|
Packit Service |
2781ba |
self->free_list = g_slist_remove (self->free_list, self->free_list->data);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, " set offset %i from free list", ((gint)entry->offset));
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
else
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
gint tile_size = gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self));
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
entry->offset = self->next_pre_alloc;
|
|
Packit Service |
2781ba |
GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, " set offset %i (next allocation)", (gint)entry->offset);
|
|
Packit Service |
2781ba |
self->next_pre_alloc += tile_size;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (self->next_pre_alloc >= self->total) /* automatic growing ensuring that
|
|
Packit Service |
2781ba |
we have room for next allocation..
|
|
Packit Service |
2781ba |
*/
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
self->total = self->total + 32 * tile_size;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "growing file to %i bytes", (gint)self->total);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
ftruncate (self->o, self->total);
|
|
Packit Service |
2781ba |
self->foffset = -1;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
gegl_tile_backend_file_dbg_alloc (gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self)));
|
|
Packit Service |
2781ba |
return entry;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static inline void
|
|
Packit Service |
2781ba |
gegl_tile_backend_file_file_entry_destroy (GeglBufferTile *entry,
|
|
Packit Service |
2781ba |
GeglTileBackendFile *self)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
/* XXX: EEEk, throwing away bits */
|
|
Packit Service |
2781ba |
guint offset = entry->offset;
|
|
Packit Service |
2781ba |
self->free_list = g_slist_prepend (self->free_list,
|
|
Packit Service |
2781ba |
GUINT_TO_POINTER (offset));
|
|
Packit Service |
2781ba |
g_hash_table_remove (self->index, entry);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gegl_tile_backend_file_dbg_dealloc (gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self)));
|
|
Packit Service |
2781ba |
g_free (entry);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static gboolean
|
|
Packit Service |
2781ba |
gegl_tile_backend_file_write_header (GeglTileBackendFile *self)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
gboolean success;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gegl_tile_backend_file_ensure_exist (self);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
success = (lseek (self->o, 0, SEEK_SET) != -1);
|
|
Packit Service |
2781ba |
if (success == FALSE)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
g_warning ("unable to seek in buffer");
|
|
Packit Service |
2781ba |
return FALSE;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
write (self->o, &(self->header), 256);
|
|
Packit Service |
2781ba |
self->foffset = 256;
|
|
Packit Service |
2781ba |
GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "Wrote header, next=%i", (gint)self->header.next);
|
|
Packit Service |
2781ba |
return TRUE;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static gboolean
|
|
Packit Service |
2781ba |
gegl_tile_backend_file_write_block (GeglTileBackendFile *self,
|
|
Packit Service |
2781ba |
GeglBufferBlock *block)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
gegl_tile_backend_file_ensure_exist (self);
|
|
Packit Service |
2781ba |
if (self->in_holding)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
guint64 next_allocation = self->offset + self->in_holding->length;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* update the next offset pointer in the previous block */
|
|
Packit Service |
2781ba |
if (block == NULL)
|
|
Packit Service |
2781ba |
/* the previous block was the last block */
|
|
Packit Service |
2781ba |
self->in_holding->next = 0;
|
|
Packit Service |
2781ba |
else
|
|
Packit Service |
2781ba |
self->in_holding->next = next_allocation;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (self->foffset != self->offset)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
if(lseek (self->o, self->offset, G_SEEK_SET) == -1)
|
|
Packit Service |
2781ba |
goto fail;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
self->foffset = self->offset;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* XXX: should promiscuosuly try to compress here as well,. if revisions
|
|
Packit Service |
2781ba |
are not matching..
|
|
Packit Service |
2781ba |
*/
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "Wrote block: length:%i flags:%i next:%i at offset %i",
|
|
Packit Service |
2781ba |
self->in_holding->length,
|
|
Packit Service |
2781ba |
self->in_holding->flags,
|
|
Packit Service |
2781ba |
(gint)self->in_holding->next,
|
|
Packit Service |
2781ba |
(gint)self->offset);
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
ssize_t written = write (self->o, self->in_holding,
|
|
Packit Service |
2781ba |
self->in_holding->length);
|
|
Packit Service |
2781ba |
if(written != -1)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
self->offset += written;
|
|
Packit Service |
2781ba |
self->foffset += written;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
g_assert (next_allocation == self->offset); /* true as long as
|
|
Packit Service |
2781ba |
the simple allocation
|
|
Packit Service |
2781ba |
scheme is used */
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
self->offset = next_allocation;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
else
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
/* we're setting up for the first write */
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
self->offset = self->next_pre_alloc; /* start writing header at end
|
|
Packit Service |
2781ba |
* of file, worry about writing
|
|
Packit Service |
2781ba |
* header inside free list later
|
|
Packit Service |
2781ba |
*/
|
|
Packit Service |
2781ba |
if (self->foffset != self->offset)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
if(lseek (self->o, self->offset, G_SEEK_SET) == -1)
|
|
Packit Service |
2781ba |
goto fail;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
self->foffset = self->offset;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
self->in_holding = block;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
return TRUE;
|
|
Packit Service |
2781ba |
fail:
|
|
Packit Service |
2781ba |
g_warning ("gegl buffer index writing problems for %s",
|
|
Packit Service |
2781ba |
self->path);
|
|
Packit Service |
2781ba |
return FALSE;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
G_DEFINE_TYPE (GeglTileBackendFile, gegl_tile_backend_file, GEGL_TYPE_TILE_BACKEND)
|
|
Packit Service |
2781ba |
static GObjectClass * parent_class = NULL;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* this debugging is across all buffers */
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static gint allocs = 0;
|
|
Packit Service |
2781ba |
static gint file_size = 0;
|
|
Packit Service |
2781ba |
static gint peak_allocs = 0;
|
|
Packit Service |
2781ba |
static gint peak_file_size = 0;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
void
|
|
Packit Service |
2781ba |
gegl_tile_backend_file_stats (void)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
g_warning ("leaked: %i chunks (%f mb) peak: %i (%i bytes %fmb))",
|
|
Packit Service |
2781ba |
allocs, file_size / 1024 / 1024.0,
|
|
Packit Service |
2781ba |
peak_allocs, peak_file_size, peak_file_size / 1024 / 1024.0);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static void
|
|
Packit Service |
2781ba |
gegl_tile_backend_file_dbg_alloc (gint size)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
allocs++;
|
|
Packit Service |
2781ba |
file_size += size;
|
|
Packit Service |
2781ba |
if (allocs > peak_allocs)
|
|
Packit Service |
2781ba |
peak_allocs = allocs;
|
|
Packit Service |
2781ba |
if (file_size > peak_file_size)
|
|
Packit Service |
2781ba |
peak_file_size = file_size;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static void
|
|
Packit Service |
2781ba |
gegl_tile_backend_file_dbg_dealloc (gint size)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
allocs--;
|
|
Packit Service |
2781ba |
file_size -= size;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static inline GeglBufferTile *
|
|
Packit Service |
2781ba |
gegl_tile_backend_file_lookup_entry (GeglTileBackendFile *self,
|
|
Packit Service |
2781ba |
gint x,
|
|
Packit Service |
2781ba |
gint y,
|
|
Packit Service |
2781ba |
gint z)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglBufferTile *ret;
|
|
Packit Service |
2781ba |
GeglBufferTile *key = gegl_tile_entry_new (x,y,z);
|
|
Packit Service |
2781ba |
ret = g_hash_table_lookup (self->index, key);
|
|
Packit Service |
2781ba |
gegl_tile_entry_destroy (key);
|
|
Packit Service |
2781ba |
return ret;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* this is the only place that actually should
|
|
Packit Service |
2781ba |
* instantiate tiles, when the cache is large enough
|
|
Packit Service |
2781ba |
* that should make sure we don't hit this function
|
|
Packit Service |
2781ba |
* too often.
|
|
Packit Service |
2781ba |
*/
|
|
Packit Service |
2781ba |
static GeglTile *
|
|
Packit Service |
2781ba |
gegl_tile_backend_file_get_tile (GeglTileSource *self,
|
|
Packit Service |
2781ba |
gint x,
|
|
Packit Service |
2781ba |
gint y,
|
|
Packit Service |
2781ba |
gint z)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglTileBackend *backend;
|
|
Packit Service |
2781ba |
GeglTileBackendFile *tile_backend_file;
|
|
Packit Service |
2781ba |
GeglBufferTile *entry;
|
|
Packit Service |
2781ba |
GeglTile *tile = NULL;
|
|
Packit Service |
2781ba |
gint tile_size;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
backend = GEGL_TILE_BACKEND (self);
|
|
Packit Service |
2781ba |
tile_backend_file = GEGL_TILE_BACKEND_FILE (backend);
|
|
Packit Service |
2781ba |
entry = gegl_tile_backend_file_lookup_entry (tile_backend_file, x, y, z);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (!entry)
|
|
Packit Service |
2781ba |
return NULL;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
tile_size = gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self));
|
|
Packit Service |
2781ba |
tile = gegl_tile_new (tile_size);
|
|
Packit Service |
2781ba |
gegl_tile_set_rev (tile, entry->rev);
|
|
Packit Service |
2781ba |
gegl_tile_mark_as_stored (tile);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gegl_tile_backend_file_file_entry_read (tile_backend_file, entry, gegl_tile_get_data (tile));
|
|
Packit Service |
2781ba |
return tile;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static gpointer
|
|
Packit Service |
2781ba |
gegl_tile_backend_file_set_tile (GeglTileSource *self,
|
|
Packit Service |
2781ba |
GeglTile *tile,
|
|
Packit Service |
2781ba |
gint x,
|
|
Packit Service |
2781ba |
gint y,
|
|
Packit Service |
2781ba |
gint z)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglTileBackend *backend;
|
|
Packit Service |
2781ba |
GeglTileBackendFile *tile_backend_file;
|
|
Packit Service |
2781ba |
GeglBufferTile *entry;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
backend = GEGL_TILE_BACKEND (self);
|
|
Packit Service |
2781ba |
tile_backend_file = GEGL_TILE_BACKEND_FILE (backend);
|
|
Packit Service |
2781ba |
entry = gegl_tile_backend_file_lookup_entry (tile_backend_file, x, y, z);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (entry == NULL)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
entry = gegl_tile_backend_file_file_entry_new (tile_backend_file);
|
|
Packit Service |
2781ba |
entry->x = x;
|
|
Packit Service |
2781ba |
entry->y = y;
|
|
Packit Service |
2781ba |
entry->z = z;
|
|
Packit Service |
2781ba |
g_hash_table_insert (tile_backend_file->index, entry, entry);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
entry->rev = gegl_tile_get_rev (tile);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gegl_tile_backend_file_file_entry_write (tile_backend_file, entry, gegl_tile_get_data (tile));
|
|
Packit Service |
2781ba |
gegl_tile_mark_as_stored (tile);
|
|
Packit Service |
2781ba |
return NULL;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static gpointer
|
|
Packit Service |
2781ba |
gegl_tile_backend_file_void_tile (GeglTileSource *self,
|
|
Packit Service |
2781ba |
GeglTile *tile,
|
|
Packit Service |
2781ba |
gint x,
|
|
Packit Service |
2781ba |
gint y,
|
|
Packit Service |
2781ba |
gint z)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglTileBackend *backend;
|
|
Packit Service |
2781ba |
GeglTileBackendFile *tile_backend_file;
|
|
Packit Service |
2781ba |
GeglBufferTile *entry;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
backend = GEGL_TILE_BACKEND (self);
|
|
Packit Service |
2781ba |
tile_backend_file = GEGL_TILE_BACKEND_FILE (backend);
|
|
Packit Service |
2781ba |
entry = gegl_tile_backend_file_lookup_entry (tile_backend_file, x, y, z);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (entry != NULL)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
gegl_tile_backend_file_file_entry_destroy (entry, tile_backend_file);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
return NULL;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static gpointer
|
|
Packit Service |
2781ba |
gegl_tile_backend_file_exist_tile (GeglTileSource *self,
|
|
Packit Service |
2781ba |
GeglTile *tile,
|
|
Packit Service |
2781ba |
gint x,
|
|
Packit Service |
2781ba |
gint y,
|
|
Packit Service |
2781ba |
gint z)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglTileBackend *backend;
|
|
Packit Service |
2781ba |
GeglTileBackendFile *tile_backend_file;
|
|
Packit Service |
2781ba |
GeglBufferTile *entry;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
backend = GEGL_TILE_BACKEND (self);
|
|
Packit Service |
2781ba |
tile_backend_file = GEGL_TILE_BACKEND_FILE (backend);
|
|
Packit Service |
2781ba |
entry = gegl_tile_backend_file_lookup_entry (tile_backend_file, x, y, z);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
return entry!=NULL?((gpointer)0x1):NULL;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static gpointer
|
|
Packit Service |
2781ba |
gegl_tile_backend_file_flush (GeglTileSource *source,
|
|
Packit Service |
2781ba |
GeglTile *tile,
|
|
Packit Service |
2781ba |
gint x,
|
|
Packit Service |
2781ba |
gint y,
|
|
Packit Service |
2781ba |
gint z)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglTileBackend *backend;
|
|
Packit Service |
2781ba |
GeglTileBackendFile *self;
|
|
Packit Service |
2781ba |
GList *tiles;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
backend = GEGL_TILE_BACKEND (source);
|
|
Packit Service |
2781ba |
self = GEGL_TILE_BACKEND_FILE (backend);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gegl_tile_backend_file_ensure_exist (self);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "flushing %s", self->path);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
self->header.rev ++;
|
|
Packit Service |
2781ba |
self->header.next = self->next_pre_alloc; /* this is the offset
|
|
Packit Service |
2781ba |
we start handing
|
|
Packit Service |
2781ba |
out headers from*/
|
|
Packit Service |
2781ba |
tiles = g_hash_table_get_keys (self->index);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (tiles == NULL)
|
|
Packit Service |
2781ba |
self->header.next = 0;
|
|
Packit Service |
2781ba |
else
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GList *iter;
|
|
Packit Service |
2781ba |
for (iter = tiles; iter; iter = iter->next)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglBufferItem *item = iter->data;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gegl_tile_backend_file_write_block (self, &item->block);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
gegl_tile_backend_file_write_block (self, NULL); /* terminate the index */
|
|
Packit Service |
2781ba |
g_list_free (tiles);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gegl_tile_backend_file_write_header (self);
|
|
Packit Service |
2781ba |
fsync (self->o);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "flushed %s", self->path);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
return (gpointer)0xf0f;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
enum
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
PROP_0,
|
|
Packit Service |
2781ba |
PROP_PATH
|
|
Packit Service |
2781ba |
};
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static gpointer
|
|
Packit Service |
2781ba |
gegl_tile_backend_file_command (GeglTileSource *self,
|
|
Packit Service |
2781ba |
GeglTileCommand command,
|
|
Packit Service |
2781ba |
gint x,
|
|
Packit Service |
2781ba |
gint y,
|
|
Packit Service |
2781ba |
gint z,
|
|
Packit Service |
2781ba |
gpointer data)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
switch (command)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
case GEGL_TILE_GET:
|
|
Packit Service |
2781ba |
return gegl_tile_backend_file_get_tile (self, x, y, z);
|
|
Packit Service |
2781ba |
case GEGL_TILE_SET:
|
|
Packit Service |
2781ba |
return gegl_tile_backend_file_set_tile (self, data, x, y, z);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
case GEGL_TILE_IDLE:
|
|
Packit Service |
2781ba |
return NULL; /* we could perhaps lazily be writing indexes
|
|
Packit Service |
2781ba |
* at some intervals, making it work as an
|
|
Packit Service |
2781ba |
* autosave for the buffer?
|
|
Packit Service |
2781ba |
*/
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
case GEGL_TILE_VOID:
|
|
Packit Service |
2781ba |
return gegl_tile_backend_file_void_tile (self, data, x, y, z);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
case GEGL_TILE_EXIST:
|
|
Packit Service |
2781ba |
return gegl_tile_backend_file_exist_tile (self, data, x, y, z);
|
|
Packit Service |
2781ba |
case GEGL_TILE_FLUSH:
|
|
Packit Service |
2781ba |
return gegl_tile_backend_file_flush (self, data, x, y, z);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
default:
|
|
Packit Service |
2781ba |
g_assert (command < GEGL_TILE_LAST_COMMAND &&
|
|
Packit Service |
2781ba |
command >= 0);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
return FALSE;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static void
|
|
Packit Service |
2781ba |
gegl_tile_backend_file_set_property (GObject *object,
|
|
Packit Service |
2781ba |
guint property_id,
|
|
Packit Service |
2781ba |
const GValue *value,
|
|
Packit Service |
2781ba |
GParamSpec *pspec)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglTileBackendFile *self = GEGL_TILE_BACKEND_FILE (object);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
switch (property_id)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
case PROP_PATH:
|
|
Packit Service |
2781ba |
if (self->path)
|
|
Packit Service |
2781ba |
g_free (self->path);
|
|
Packit Service |
2781ba |
self->path = g_value_dup_string (value);
|
|
Packit Service |
2781ba |
break;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
default:
|
|
Packit Service |
2781ba |
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
Packit Service |
2781ba |
break;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static void
|
|
Packit Service |
2781ba |
gegl_tile_backend_file_get_property (GObject *object,
|
|
Packit Service |
2781ba |
guint property_id,
|
|
Packit Service |
2781ba |
GValue *value,
|
|
Packit Service |
2781ba |
GParamSpec *pspec)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglTileBackendFile *self = GEGL_TILE_BACKEND_FILE (object);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
switch (property_id)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
case PROP_PATH:
|
|
Packit Service |
2781ba |
g_value_set_string (value, self->path);
|
|
Packit Service |
2781ba |
break;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
default:
|
|
Packit Service |
2781ba |
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
Packit Service |
2781ba |
break;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static void
|
|
Packit Service |
2781ba |
gegl_tile_backend_file_finalize (GObject *object)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglTileBackendFile *self = (GeglTileBackendFile *) object;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (self->index)
|
|
Packit Service |
2781ba |
g_hash_table_unref (self->index);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (self->exist)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "finalizing buffer %s", self->path);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (self->i != -1)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
close (self->i);
|
|
Packit Service |
2781ba |
self->i = -1;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
if (self->o != -1)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
close (self->o);
|
|
Packit Service |
2781ba |
self->o = -1;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (self->path)
|
|
Packit Service |
2781ba |
g_free (self->path);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (self->monitor)
|
|
Packit Service |
2781ba |
g_object_unref (self->monitor);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (self->file)
|
|
Packit Service |
2781ba |
g_object_unref (self->file);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
(*G_OBJECT_CLASS (parent_class)->finalize)(object);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static guint
|
|
Packit Service |
2781ba |
gegl_tile_backend_file_hashfunc (gconstpointer key)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
const GeglBufferTile *e = key;
|
|
Packit Service |
2781ba |
guint hash;
|
|
Packit Service |
2781ba |
gint i;
|
|
Packit Service |
2781ba |
gint srcA = e->x;
|
|
Packit Service |
2781ba |
gint srcB = e->y;
|
|
Packit Service |
2781ba |
gint srcC = e->z;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* interleave the 10 least significant bits of all coordinates,
|
|
Packit Service |
2781ba |
* this gives us Z-order / morton order of the space and should
|
|
Packit Service |
2781ba |
* work well as a hash
|
|
Packit Service |
2781ba |
*/
|
|
Packit Service |
2781ba |
hash = 0;
|
|
Packit Service |
2781ba |
for (i = 9; i >= 0; i--)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
#define ADD_BIT(bit) do { hash |= (((bit) != 0) ? 1 : 0); hash <<= 1; } while (0)
|
|
Packit Service |
2781ba |
ADD_BIT (srcA & (1 << i));
|
|
Packit Service |
2781ba |
ADD_BIT (srcB & (1 << i));
|
|
Packit Service |
2781ba |
ADD_BIT (srcC & (1 << i));
|
|
Packit Service |
2781ba |
#undef ADD_BIT
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
return hash;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static gboolean
|
|
Packit Service |
2781ba |
gegl_tile_backend_file_equalfunc (gconstpointer a,
|
|
Packit Service |
2781ba |
gconstpointer b)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
const GeglBufferTile *ea = a;
|
|
Packit Service |
2781ba |
const GeglBufferTile *eb = b;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (ea->x == eb->x &&
|
|
Packit Service |
2781ba |
ea->y == eb->y &&
|
|
Packit Service |
2781ba |
ea->z == eb->z)
|
|
Packit Service |
2781ba |
return TRUE;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
return FALSE;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static void
|
|
Packit Service |
2781ba |
gegl_tile_backend_file_load_index (GeglTileBackendFile *self,
|
|
Packit Service |
2781ba |
gboolean block)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglBufferHeader new_header;
|
|
Packit Service |
2781ba |
GList *iter;
|
|
Packit Service |
2781ba |
GeglTileBackend *backend;
|
|
Packit Service |
2781ba |
goffset offset = 0;
|
|
Packit Service |
2781ba |
goffset max=0;
|
|
Packit Service |
2781ba |
gint tile_size;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* compute total from and next pre alloc by monitoring tiles as they
|
|
Packit Service |
2781ba |
* are added here
|
|
Packit Service |
2781ba |
*/
|
|
Packit Service |
2781ba |
/* reload header */
|
|
Packit Service |
2781ba |
new_header = gegl_buffer_read_header (self->i, &offset)->header;
|
|
Packit Service |
2781ba |
self->foffset = 256;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
while (new_header.flags & GEGL_FLAG_LOCKED)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
g_usleep (50000);
|
|
Packit Service |
2781ba |
new_header = gegl_buffer_read_header (self->i, &offset)->header;
|
|
Packit Service |
2781ba |
self->foffset = 256;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (new_header.rev == self->header.rev)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GEGL_NOTE(GEGL_DEBUG_TILE_BACKEND, "header not changed: %s", self->path);
|
|
Packit Service |
2781ba |
return;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
else
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
self->header=new_header;
|
|
Packit Service |
2781ba |
GEGL_NOTE(GEGL_DEBUG_TILE_BACKEND, "loading index: %s", self->path);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
tile_size = gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self));
|
|
Packit Service |
2781ba |
offset = self->header.next;
|
|
Packit Service |
2781ba |
self->tiles = gegl_buffer_read_index (self->i, &offset);
|
|
Packit Service |
2781ba |
self->foffset = -1;
|
|
Packit Service |
2781ba |
backend = GEGL_TILE_BACKEND (self);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
for (iter = self->tiles; iter; iter=iter->next)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglBufferItem *item = iter->data;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
GeglBufferItem *existing = g_hash_table_lookup (self->index, item);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (item->tile.offset > max)
|
|
Packit Service |
2781ba |
max = item->tile.offset + tile_size;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (existing)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
if (existing->tile.rev == item->tile.rev)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
g_assert (existing->tile.offset == item->tile.offset);
|
|
Packit Service |
2781ba |
existing->tile = item->tile;
|
|
Packit Service |
2781ba |
g_free (item);
|
|
Packit Service |
2781ba |
continue;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
else
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglTileStorage *storage =
|
|
Packit Service |
2781ba |
(void*)gegl_tile_backend_peek_storage (backend);
|
|
Packit Service |
2781ba |
GeglRectangle rect;
|
|
Packit Service |
2781ba |
g_hash_table_remove (self->index, existing);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gegl_tile_source_refetch (GEGL_TILE_SOURCE (storage),
|
|
Packit Service |
2781ba |
existing->tile.x,
|
|
Packit Service |
2781ba |
existing->tile.y,
|
|
Packit Service |
2781ba |
existing->tile.z);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (existing->tile.z == 0)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
rect.width = self->header.tile_width;
|
|
Packit Service |
2781ba |
rect.height = self->header.tile_height;
|
|
Packit Service |
2781ba |
rect.x = existing->tile.x * self->header.tile_width;
|
|
Packit Service |
2781ba |
rect.y = existing->tile.y * self->header.tile_height;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
g_free (existing);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
g_signal_emit_by_name (storage, "changed", &rect, NULL);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
g_hash_table_insert (self->index, iter->data, iter->data);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
g_list_free (self->tiles);
|
|
Packit Service |
2781ba |
g_slist_free (self->free_list);
|
|
Packit Service |
2781ba |
self->free_list = NULL;
|
|
Packit Service |
2781ba |
self->next_pre_alloc = max; /* if bigger than own? */
|
|
Packit Service |
2781ba |
self->total = max;
|
|
Packit Service |
2781ba |
self->tiles = NULL;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static void
|
|
Packit Service |
2781ba |
gegl_tile_backend_file_file_changed (GFileMonitor *monitor,
|
|
Packit Service |
2781ba |
GFile *file,
|
|
Packit Service |
2781ba |
GFile *other_file,
|
|
Packit Service |
2781ba |
GFileMonitorEvent event_type,
|
|
Packit Service |
2781ba |
GeglTileBackendFile *self)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
if (event_type == G_FILE_MONITOR_EVENT_CHANGED /*G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT*/ )
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
gegl_tile_backend_file_load_index (self, TRUE);
|
|
Packit Service |
2781ba |
self->foffset = -1;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static GObject *
|
|
Packit Service |
2781ba |
gegl_tile_backend_file_constructor (GType type,
|
|
Packit Service |
2781ba |
guint n_params,
|
|
Packit Service |
2781ba |
GObjectConstructParam *params)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GObject *object;
|
|
Packit Service |
2781ba |
GeglTileBackendFile *self;
|
|
Packit Service |
2781ba |
GeglTileBackend *backend;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
object = G_OBJECT_CLASS (parent_class)->constructor (type, n_params, params);
|
|
Packit Service |
2781ba |
self = GEGL_TILE_BACKEND_FILE (object);
|
|
Packit Service |
2781ba |
backend = GEGL_TILE_BACKEND (object);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "constructing file backend: %s", self->path);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
self->file = g_file_new_for_commandline_arg (self->path);
|
|
Packit Service |
2781ba |
self->i = self->o = -1;
|
|
Packit Service |
2781ba |
self->index = g_hash_table_new (gegl_tile_backend_file_hashfunc, gegl_tile_backend_file_equalfunc);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* If the file already exists open it, assuming it is a GeglBuffer. */
|
|
Packit Service |
2781ba |
if (access (self->path, F_OK) != -1)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
goffset offset = 0;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* Install a monitor for changes to the file in case other applications
|
|
Packit Service |
2781ba |
* might be writing to the buffer
|
|
Packit Service |
2781ba |
*/
|
|
Packit Service |
2781ba |
self->monitor = g_file_monitor_file (self->file, G_FILE_MONITOR_NONE,
|
|
Packit Service |
2781ba |
NULL, NULL);
|
|
Packit Service |
2781ba |
g_signal_connect (self->monitor, "changed",
|
|
Packit Service |
2781ba |
G_CALLBACK (gegl_tile_backend_file_file_changed),
|
|
Packit Service |
2781ba |
self);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
self->o = open (self->path, O_RDWR|O_CREAT, 0770);
|
|
Packit Service |
2781ba |
if (self->o == -1)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
/* Try again but this time with only read access. This is
|
|
Packit Service |
2781ba |
* a quick-fix for make distcheck, where img_cmp fails
|
|
Packit Service |
2781ba |
* when it opens a GeglBuffer file in the source tree
|
|
Packit Service |
2781ba |
* (which is read-only).
|
|
Packit Service |
2781ba |
*/
|
|
Packit Service |
2781ba |
self->o = open (self->path, O_RDONLY, 0770);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (self->o == -1)
|
|
Packit Service |
2781ba |
g_warning ("%s: Could not open '%s': %s", G_STRFUNC, self->path, g_strerror (errno));
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
self->i = dup (self->o);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
self->header = gegl_buffer_read_header (self->i, &offset)->header;
|
|
Packit Service |
2781ba |
self->header.rev = self->header.rev -1;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* we are overriding all of the work of the actual constructor here,
|
|
Packit Service |
2781ba |
* a really evil hack :d
|
|
Packit Service |
2781ba |
*/
|
|
Packit Service |
2781ba |
backend->priv->tile_width = self->header.tile_width;
|
|
Packit Service |
2781ba |
backend->priv->tile_height = self->header.tile_height;
|
|
Packit Service |
2781ba |
backend->priv->format = babl_format (self->header.description);
|
|
Packit Service |
2781ba |
backend->priv->px_size = babl_format_get_bytes_per_pixel (backend->priv->format);
|
|
Packit Service |
2781ba |
backend->priv->tile_size = backend->priv->tile_width *
|
|
Packit Service |
2781ba |
backend->priv->tile_height *
|
|
Packit Service |
2781ba |
backend->priv->px_size;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* insert each of the entries into the hash table */
|
|
Packit Service |
2781ba |
gegl_tile_backend_file_load_index (self, TRUE);
|
|
Packit Service |
2781ba |
self->exist = TRUE;
|
|
Packit Service |
2781ba |
g_assert (self->i != -1);
|
|
Packit Service |
2781ba |
g_assert (self->o != -1);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* to autoflush gegl_buffer_set */
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* XXX: poking at internals, icky */
|
|
Packit Service |
2781ba |
backend->priv->shared = TRUE;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
else
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
self->exist = FALSE; /* this is also the default, the file will be created on demand */
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
g_assert (self->file);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
backend->priv->header = &self->header;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
return object;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static void
|
|
Packit Service |
2781ba |
gegl_tile_backend_file_ensure_exist (GeglTileBackendFile *self)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
if (!self->exist)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglTileBackend *backend;
|
|
Packit Service |
2781ba |
self->exist = TRUE;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
backend = GEGL_TILE_BACKEND (self);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "creating swapfile %s", self->path);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
self->o = open (self->path, O_RDWR|O_CREAT, 0770);
|
|
Packit Service |
2781ba |
if (self->o == -1)
|
|
Packit Service |
2781ba |
g_warning ("%s: Could not open '%s': %s", G_STRFUNC, self->path, g_strerror (errno));
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
self->next_pre_alloc = 256; /* reserved space for header */
|
|
Packit Service |
2781ba |
self->total = 256; /* reserved space for header */
|
|
Packit Service |
2781ba |
self->foffset = 0;
|
|
Packit Service |
2781ba |
gegl_buffer_header_init (&self->header,
|
|
Packit Service |
2781ba |
backend->priv->tile_width,
|
|
Packit Service |
2781ba |
backend->priv->tile_height,
|
|
Packit Service |
2781ba |
backend->priv->px_size,
|
|
Packit Service |
2781ba |
backend->priv->format
|
|
Packit Service |
2781ba |
);
|
|
Packit Service |
2781ba |
gegl_tile_backend_file_write_header (self);
|
|
Packit Service |
2781ba |
self->foffset = 256;
|
|
Packit Service |
2781ba |
fsync (self->o);
|
|
Packit Service |
2781ba |
self->i = dup (self->o);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/*self->i = G_INPUT_STREAM (g_file_read (self->file, NULL, NULL));*/
|
|
Packit Service |
2781ba |
self->next_pre_alloc = 256; /* reserved space for header */
|
|
Packit Service |
2781ba |
self->total = 256; /* reserved space for header */
|
|
Packit Service |
2781ba |
g_assert (self->i != -1);
|
|
Packit Service |
2781ba |
g_assert (self->o != -1);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static void
|
|
Packit Service |
2781ba |
gegl_tile_backend_file_class_init (GeglTileBackendFileClass *klass)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
parent_class = g_type_class_peek_parent (klass);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gobject_class->get_property = gegl_tile_backend_file_get_property;
|
|
Packit Service |
2781ba |
gobject_class->set_property = gegl_tile_backend_file_set_property;
|
|
Packit Service |
2781ba |
gobject_class->constructor = gegl_tile_backend_file_constructor;
|
|
Packit Service |
2781ba |
gobject_class->finalize = gegl_tile_backend_file_finalize;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
GEGL_BUFFER_STRUCT_CHECK_PADDING;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
g_object_class_install_property (gobject_class, PROP_PATH,
|
|
Packit Service |
2781ba |
g_param_spec_string ("path",
|
|
Packit Service |
2781ba |
"path",
|
|
Packit Service |
2781ba |
"The base path for this backing file for a buffer",
|
|
Packit Service |
2781ba |
NULL,
|
|
Packit Service |
2781ba |
G_PARAM_CONSTRUCT |
|
|
Packit Service |
2781ba |
G_PARAM_READWRITE));
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static void
|
|
Packit Service |
2781ba |
gegl_tile_backend_file_init (GeglTileBackendFile *self)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
((GeglTileSource*)self)->command = gegl_tile_backend_file_command;
|
|
Packit Service |
2781ba |
self->path = NULL;
|
|
Packit Service |
2781ba |
self->file = NULL;
|
|
Packit Service |
2781ba |
self->i = -1;
|
|
Packit Service |
2781ba |
self->o = -1;
|
|
Packit Service |
2781ba |
self->index = NULL;
|
|
Packit Service |
2781ba |
self->free_list = NULL;
|
|
Packit Service |
2781ba |
self->next_pre_alloc = 256; /* reserved space for header */
|
|
Packit Service |
2781ba |
self->total = 256; /* reserved space for header */
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gboolean
|
|
Packit Service |
2781ba |
gegl_tile_backend_file_try_lock (GeglTileBackendFile *self)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglBufferHeader new_header;
|
|
Packit Service |
2781ba |
new_header = gegl_buffer_read_header (self->i, NULL)->header;
|
|
Packit Service |
2781ba |
if (new_header.flags & GEGL_FLAG_LOCKED)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
return FALSE;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
self->header.flags += GEGL_FLAG_LOCKED;
|
|
Packit Service |
2781ba |
gegl_tile_backend_file_write_header (self);
|
|
Packit Service |
2781ba |
fsync (self->o);
|
|
Packit Service |
2781ba |
return TRUE;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gboolean
|
|
Packit Service |
2781ba |
gegl_tile_backend_file_unlock (GeglTileBackendFile *self)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
if (!(self->header.flags & GEGL_FLAG_LOCKED))
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
g_warning ("tried to unlock unlocked buffer");
|
|
Packit Service |
2781ba |
return FALSE;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
self->header.flags -= GEGL_FLAG_LOCKED;
|
|
Packit Service |
2781ba |
gegl_tile_backend_file_write_header (self);
|
|
Packit Service |
2781ba |
fsync (self->o);
|
|
Packit Service |
2781ba |
return TRUE;
|
|
Packit Service |
2781ba |
}
|