static gboolean
gegl_tile_backend_file_write_header (GeglTileBackendFile *self)
{
  gboolean success;

  gegl_tile_backend_file_ensure_exist (self);

#if HAVE_GIO
  success = g_seekable_seek (G_SEEKABLE (self->o), 0, G_SEEK_SET,
                             NULL, NULL);
#else
  success = (lseek (self->o, 0, SEEK_SET) != -1);
#endif
  if (success == FALSE)
    {
      g_warning ("unable to seek in buffer");
      return FALSE;
    }
#if HAVE_GIO
  g_output_stream_write (self->o, &(self->header), 256, NULL, NULL);
#else
  write (self->o, &(self->header), 256);
#endif
  GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "Wrote header, next=%i", (gint)self->header.next);
  return TRUE;
}
static gpointer
gegl_tile_backend_file_flush (GeglTileSource *source,
                              GeglTile       *tile,
                              gint            x,
                              gint            y,
                              gint            z)
{
  GeglTileBackend     *backend;
  GeglTileBackendFile *self;
  GList               *tiles;

  backend  = GEGL_TILE_BACKEND (source);
  self     = GEGL_TILE_BACKEND_FILE (backend);

  gegl_tile_backend_file_ensure_exist (self);

  GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "flushing %s", self->path);


  self->header.rev ++;
  self->header.next = self->next_pre_alloc; /* this is the offset
                                               we start handing
                                               out headers from*/
  tiles = g_hash_table_get_keys (self->index);

  if (tiles == NULL)
    self->header.next = 0;
  else
    {
      GList *iter;
      for (iter = tiles; iter; iter = iter->next)
        {
          GeglBufferItem *item = iter->data;

          gegl_tile_backend_file_write_block (self, &item->block);
        }
      gegl_tile_backend_file_write_block (self, NULL); /* terminate the index */
      g_list_free (tiles);
    }

  gegl_tile_backend_file_write_header (self);
#if HAVE_GIO
  g_output_stream_flush (self->o, NULL, NULL);
#else
  fsync (self->o);
#endif

  GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "flushed %s", self->path);

  return (gpointer)0xf0f;
}
static inline void
gegl_tile_backend_file_file_entry_read (GeglTileBackendFile *self,
                                        GeglBufferTile      *entry,
                                        guchar              *dest)
{
  gint     to_be_read;
  gboolean success;
  gint     tile_size = gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self));
  goffset  offset = entry->offset;

  gegl_tile_backend_file_ensure_exist (self);

#if HAVE_GIO
  success = g_seekable_seek (G_SEEKABLE (self->i),
                             offset, G_SEEK_SET,
                             NULL, NULL);
#else
  success = (lseek (self->i, offset, SEEK_SET) >= 0);
#endif
  if (success == FALSE)
    {
      g_warning ("unable to seek to tile in buffer: %s", g_strerror (errno));
      return;
    }
  to_be_read = tile_size;

  while (to_be_read > 0)
    {
      gint byte_read;

#if HAVE_GIO
      byte_read = g_input_stream_read (G_INPUT_STREAM (self->i),
                                       dest + tile_size - to_be_read, to_be_read,
                                       NULL, NULL);
#else
      byte_read = read (self->i, dest + tile_size - to_be_read, to_be_read);
#endif
      if (byte_read <= 0)
        {
          g_message ("unable to read tile data from self: "
                     "%s (%d/%d bytes read)",
                     g_strerror (errno), byte_read, to_be_read);
          return;
        }
      to_be_read -= byte_read;
    }


  GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "read entry %i,%i,%i at %i", entry->x, entry->y, entry->z, (gint)offset);
}
static inline void
gegl_tile_backend_file_file_entry_write (GeglTileBackendFile *self,
                                         GeglBufferTile      *entry,
                                         guchar              *source)
{
  gint     to_be_written;
  gboolean success;
  gint     tile_size = gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self));
  goffset  offset = entry->offset;

  gegl_tile_backend_file_ensure_exist (self);

#if HAVE_GIO
  success = g_seekable_seek (G_SEEKABLE (self->o),
                             offset, G_SEEK_SET,
                             NULL, NULL);
#else
  success = (lseek (self->o, offset, SEEK_SET) >= 0);
#endif
  if (success == FALSE)
    {
      g_warning ("unable to seek to tile in buffer: %s", g_strerror (errno));
      return;
    }
  to_be_written = tile_size;

  while (to_be_written > 0)
    {
      gint wrote;
#if HAVE_GIO
      wrote = g_output_stream_write (self->o,
                                     source + tile_size - to_be_written,
                                     to_be_written, NULL, NULL);
#else
      wrote = write (self->o,
                     source + tile_size - to_be_written,
                     to_be_written);
#endif
      if (wrote <= 0)
        {
          g_message ("unable to write tile data to self: "
                     "%s (%d/%d bytes written)",
                     g_strerror (errno), wrote, to_be_written);
          return;
        }
      to_be_written -= wrote;
    }
  GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "wrote entry %i,%i,%i at %i", entry->x, entry->y, entry->z, (gint)offset);
}
static inline void
gegl_tile_backend_file_file_entry_read (GeglTileBackendFile *self,
                                        GeglBufferTile      *entry,
                                        guchar              *dest)
{
  gint     to_be_read;
  gboolean success;
  gint     tile_size = gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self));
  goffset  offset = entry->offset;
  guchar  *tdest = dest;

  gegl_tile_backend_file_ensure_exist (self);

  if (self->foffset != offset)
    {
      success = (lseek (self->i, offset, SEEK_SET) >= 0);

      if (success == FALSE)
        {
          g_warning ("unable to seek to tile in buffer: %s", g_strerror (errno));
          return;
        }
      self->foffset = offset;
    }
  to_be_read = tile_size;

  while (to_be_read > 0)
    {
      GError *error = NULL;
      gint byte_read;

      byte_read = read (self->i, tdest + tile_size - to_be_read, to_be_read);
      if (byte_read <= 0)
        {
          g_message ("unable to read tile data from self: "
                     "%s (%d/%d bytes read) %s",
                     g_strerror (errno), byte_read, to_be_read, error?error->message:"--");
          return;
        }
      to_be_read -= byte_read;
      self->foffset += byte_read;
    }

  GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "read entry %i,%i,%i at %i", entry->x, entry->y, entry->z, (gint)offset);
}
static gboolean
gegl_tile_backend_file_write_header (GeglTileBackendFile *self)
{
  gboolean success;

  gegl_tile_backend_file_ensure_exist (self);

  success = (lseek (self->o, 0, SEEK_SET) != -1);
  if (success == FALSE)
    {
      g_warning ("unable to seek in buffer");
      return FALSE;
    }
  write (self->o, &(self->header), 256);
  self->foffset = 256;
  GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "Wrote header, next=%i", (gint)self->header.next);
  return TRUE;
}
static inline GeglBufferTile *
gegl_tile_backend_file_file_entry_new (GeglTileBackendFile *self)
{
  GeglBufferTile *entry = gegl_tile_entry_new (0,0,0);

  GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "Creating new entry");

  gegl_tile_backend_file_ensure_exist (self);

  if (self->free_list)
    {
      /* XXX: losing precision ?
       * the free list seems to operate with fixed size datums and
       * only keep track of offsets.
       */
      gint offset = GPOINTER_TO_INT (self->free_list->data);
      entry->offset = offset;
      self->free_list = g_slist_remove (self->free_list, self->free_list->data);

      GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "  set offset %i from free list", ((gint)entry->offset));
    }
  else
    {
      gint tile_size = gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self));

      entry->offset = self->next_pre_alloc;
      GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "  set offset %i (next allocation)", (gint)entry->offset);
      self->next_pre_alloc += tile_size;

      if (self->next_pre_alloc >= self->total) /* automatic growing ensuring that
                                                  we have room for next allocation..
                                                */
        {
          self->total = self->total + 32 * tile_size;

          GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "growing file to %i bytes", (gint)self->total);

          ftruncate (self->o, self->total);
          self->foffset = -1;
        }
    }
  gegl_tile_backend_file_dbg_alloc (gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self)));
  return entry;
}
static inline GeglBufferTile *
gegl_tile_backend_file_file_entry_new (GeglTileBackendFile *self)
{
  GeglBufferTile *entry = gegl_tile_entry_new (0,0,0);

  GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "Creating new entry");

  gegl_tile_backend_file_ensure_exist (self);

  if (self->free_list)
    {
      /* XXX: losing precision ? */
      gint offset = GPOINTER_TO_INT (self->free_list->data);
      entry->offset = offset;
      self->free_list = g_slist_remove (self->free_list, self->free_list->data);

      GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "  set offset %i from free list", ((gint)entry->offset));
    }
  else
    {
      gint tile_size = gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self));

      entry->offset = self->next_pre_alloc;
      GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "  set offset %i (next allocation)", (gint)entry->offset);
      self->next_pre_alloc += tile_size;

      if (self->next_pre_alloc >= self->total)
        {
          self->total = self->total + 32 * tile_size;

          GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "growing file to %i bytes", (gint)self->total);

#if HAVE_GIO
          g_assert (g_seekable_truncate (G_SEEKABLE (self->o),
                                         self->total, NULL,NULL));
#else
          g_assert (ftruncate (self->o, self->total) == 0);
#endif
        }
    }
  gegl_tile_backend_file_dbg_alloc (gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self)));
  return entry;
}
static gboolean
gegl_tile_backend_file_write_block (GeglTileBackendFile *self,
                                    GeglBufferBlock     *block)
{
  gegl_tile_backend_file_ensure_exist (self);
  if (self->in_holding)
    {
      guint64 next_allocation = self->offset + self->in_holding->length;


      /* update the next offset pointer in the previous block */
      if (block == NULL)
          /* the previous block was the last block */
          self->in_holding->next = 0;
      else
          self->in_holding->next = next_allocation;

      if (self->foffset != self->offset)
      {
        if(lseek (self->o, self->offset, G_SEEK_SET) == -1)
          goto fail;

        self->foffset = self->offset;
      }

      /* XXX: should promiscuosuly try to compress here as well,. if revisions
              are not matching..
       */

      GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "Wrote block: length:%i flags:%i next:%i at offset %i",
                 self->in_holding->length,
                 self->in_holding->flags,
                 (gint)self->in_holding->next,
                 (gint)self->offset);
      {
        ssize_t written = write (self->o, self->in_holding,
                                 self->in_holding->length);
        if(written != -1)
          {
            self->offset += written;
            self->foffset += written;
          }
      }

      g_assert (next_allocation == self->offset); /* true as long as
                                                     the simple allocation
                                                     scheme is used */

      self->offset = next_allocation;
    }
  else
    {
      /* we're setting up for the first write */

      self->offset = self->next_pre_alloc; /* start writing header at end
                                            * of file, worry about writing
                                            * header inside free list later
                                            */
      if (self->foffset != self->offset)
      {
        if(lseek (self->o, self->offset, G_SEEK_SET) == -1)
          goto fail;

        self->foffset = self->offset;
      }
    }
  self->in_holding = block;

  return TRUE;
fail:
  g_warning ("gegl buffer index writing problems for %s",
             self->path);
  return FALSE;
}
示例#10
0
static gboolean
gegl_tile_backend_file_write_block (GeglTileBackendFile *self,
                                    GeglBufferBlock     *block)
{
  gegl_tile_backend_file_ensure_exist (self);
  if (self->in_holding)
    {
      guint64 next_allocation = self->offset + self->in_holding->length;

      /* update the next offset pointer in the previous block */
      self->in_holding->next = next_allocation;

      if (block == NULL) /* the previous block was the last block */
        {
          self->in_holding->next = 0;
        }

#if HAVE_GIO
      if(!g_seekable_seek (G_SEEKABLE (self->o),
                           self->offset, G_SEEK_SET,
                           NULL, NULL))
#else
      if(lseek (self->o, self->offset, G_SEEK_SET) == -1)
#endif
        goto fail;

      GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "Wrote block: length:%i flags:%i next:%i at offset %i",
                 self->in_holding->length,
                 self->in_holding->flags,
                 (gint)self->in_holding->next,
                 (gint)self->offset);
#if HAVE_GIO
      self->offset += g_output_stream_write (self->o, self->in_holding,
                                             self->in_holding->length,
                                             NULL, NULL);
#else
      {
        ssize_t written = write (self->o, self->in_holding,
                                 self->in_holding->length);
        if(written != -1)
          self->offset += written;
      }
#endif

      g_assert (next_allocation == self->offset); /* true as long as
                                                     the simple allocation
                                                     scheme is used */

      self->offset = next_allocation;
    }
  else
    {
      /* we're setting up for the first write */

      self->offset = self->next_pre_alloc; /* start writing header at end
                                            * of file, worry about writing
                                            * header inside free list later
                                            */
#if HAVE_GIO
      if(!g_seekable_seek (G_SEEKABLE (self->o),
                           (goffset) self->offset, G_SEEK_SET,
                           NULL, NULL))
#else
      if(lseek (self->o, self->offset, G_SEEK_SET) == -1)
#endif
        goto fail;
    }
  self->in_holding = block;

  return TRUE;
fail:
  g_warning ("gegl buffer index writing problems for %s",
             self->path);
  return FALSE;
}