Blame gegl/buffer/gegl-tile-backend-file.c

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
}