gboolean
gegl_tile_backend_file_try_lock (GeglTileBackendFile *self)
{
  GeglBufferHeader new_header;
  new_header = gegl_buffer_read_header (self->i, NULL)->header;
  if (new_header.flags & GEGL_FLAG_LOCKED)
    {
      return FALSE;
    }
  self->header.flags += GEGL_FLAG_LOCKED;
  gegl_tile_backend_file_write_header (self);
  fsync (self->o);
  return TRUE;
}
gboolean
gegl_tile_backend_file_try_lock (GeglTileBackendFile *self)
{
  GeglBufferHeader new_header;
  new_header = gegl_buffer_read_header (self->i, NULL)->header;
  if (new_header.flags & GEGL_FLAG_LOCKED)
    {
      return FALSE;
    }
  self->header.flags += GEGL_FLAG_LOCKED;
  gegl_tile_backend_file_write_header (self);
#if HAVE_GIO
  g_output_stream_flush (self->o, NULL, NULL);
#else
  fsync (self->o);
#endif
  return TRUE;
}
Example #3
0
GeglBuffer *
gegl_buffer_load (const gchar *path)
{
  GeglBuffer *ret;

  LoadInfo *info = g_slice_new0 (LoadInfo);

  info->path = g_strdup (path);
  info->i = g_open (info->path, O_RDONLY, 0770);
  GEGL_NOTE (GEGL_DEBUG_BUFFER_LOAD, "starting to load buffer %s", path);
  if (info->i == -1)
    {
      GEGL_NOTE (GEGL_DEBUG_BUFFER_LOAD, "failed top open %s for reading", path);
      return NULL;
    }

  {
    GeglBufferItem *header = gegl_buffer_read_header (info->i, &info->offset);
    g_assert (header);
    /*memcpy (&(info->header), header, sizeof (GeglBufferHeader));*/
    info->header = *(&header->header);
    info->offset = info->header.next;
    /*g_free (header);*/  /* is there a pointer to a string or something we're missing? */
  }



  info->tile_size    = info->header.tile_width *
                       info->header.tile_height *
                       info->header.bytes_per_pixel;
  info->format       = babl_format (info->header.description);

  ret = g_object_new (GEGL_TYPE_BUFFER,
                      "format", info->format,
                      "tile-width", info->header.tile_width,
                      "tile-height", info->header.tile_height,
                      "height", info->header.height,
                      "width", info->header.width,
                      "path", path,
                      NULL);

  /* sanity check, should probably report error condition and return safely instead
  */
  g_assert (babl_format_get_bytes_per_pixel (info->format) == info->header.bytes_per_pixel);

  info->tiles = gegl_buffer_read_index (info->i, &info->offset);

  /* load each tile */
  {
    GList *iter;
    gint   i = 0;
    for (iter = info->tiles; iter; iter = iter->next)
      {
        GeglBufferTile *entry = iter->data;
        guchar         *data;
        GeglTile       *tile;


        tile = gegl_tile_source_get_tile (GEGL_TILE_SOURCE (ret),
                                          entry->x,
                                          entry->y,
                                          entry->z);

        if (info->offset != entry->offset)
          {
            seekto (info, entry->offset);
          }
        /*g_assert (info->offset == entry->offset);*/


        g_assert (tile);
        gegl_tile_lock (tile);

        data = gegl_tile_get_data (tile);
        g_assert (data);

        {
          ssize_t sz_read = read (info->i, data, info->tile_size);
          if(sz_read != -1)
            info->offset += sz_read;
        }
        /*g_assert (info->offset == entry->offset + info->tile_size);*/

        gegl_tile_unlock (tile);
        gegl_tile_unref (tile);
        i++;
      }
    GEGL_NOTE (GEGL_DEBUG_BUFFER_LOAD, "%i tiles loaded",i);
  }
  GEGL_NOTE (GEGL_DEBUG_BUFFER_LOAD, "buffer loaded %s", info->path);

  load_info_destroy (info);
  return ret;
}
static GObject *
gegl_tile_backend_file_constructor (GType                  type,
                                    guint                  n_params,
                                    GObjectConstructParam *params)
{
  GObject             *object;
  GeglTileBackendFile *self;
  GeglTileBackend     *backend;

  object  = G_OBJECT_CLASS (parent_class)->constructor (type, n_params, params);
  self    = GEGL_TILE_BACKEND_FILE (object);
  backend = GEGL_TILE_BACKEND (object);

  GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "constructing file backend: %s", self->path);

  self->file = g_file_new_for_commandline_arg (self->path);
  self->i = self->o = -1;
  self->index = g_hash_table_new (gegl_tile_backend_file_hashfunc, gegl_tile_backend_file_equalfunc);


  /* If the file already exists open it, assuming it is a GeglBuffer. */
  if (g_access (self->path, F_OK) != -1)
    {
      goffset offset = 0;

      /* Install a monitor for changes to the file in case other applications
       * might be writing to the buffer
       */
      self->monitor = g_file_monitor_file (self->file, G_FILE_MONITOR_NONE,
                                           NULL, NULL);
      g_signal_connect (self->monitor, "changed",
                        G_CALLBACK (gegl_tile_backend_file_file_changed),
                        self);

      self->o = g_open (self->path, O_RDWR|O_CREAT, 0770);
      if (self->o == -1)
        {
          /* Try again but this time with only read access. This is
           * a quick-fix for make distcheck, where img_cmp fails
           * when it opens a GeglBuffer file in the source tree
           * (which is read-only).
           */
          self->o = g_open (self->path, O_RDONLY, 0770);

          if (self->o == -1)
            g_warning ("%s: Could not open '%s': %s", G_STRFUNC, self->path, g_strerror (errno));
        }
      self->i = dup (self->o);

      self->header = gegl_buffer_read_header (self->i, &offset)->header;
      self->header.rev = self->header.rev -1;

      /* we are overriding all of the work of the actual constructor here,
       * a really evil hack :d
       */
      backend->priv->tile_width = self->header.tile_width;
      backend->priv->tile_height = self->header.tile_height;
      backend->priv->format = babl_format (self->header.description);
      backend->priv->px_size = babl_format_get_bytes_per_pixel (backend->priv->format);
      backend->priv->tile_size = backend->priv->tile_width *
                                    backend->priv->tile_height *
                                    backend->priv->px_size;

      /* insert each of the entries into the hash table */
      gegl_tile_backend_file_load_index (self, TRUE);
      self->exist = TRUE;
      g_assert (self->i != -1);
      g_assert (self->o != -1);

      /* to autoflush gegl_buffer_set */

      /* XXX: poking at internals, icky */
      backend->priv->shared = TRUE;
    }
  else
    {
      self->exist = FALSE; /* this is also the default, the file will be created on demand */
    }

  g_assert (self->file);

  backend->priv->header = &self->header;

  return object;
}
static void
gegl_tile_backend_file_load_index (GeglTileBackendFile *self,
                                   gboolean             block)
{
  GeglBufferHeader new_header;
  GList           *iter;
  GeglTileBackend *backend;
  goffset offset = 0;
  goffset max=0;
  gint tile_size;

  /* compute total from and next pre alloc by monitoring tiles as they
   * are added here
   */
  /* reload header */
  new_header = gegl_buffer_read_header (self->i, &offset)->header;
  self->foffset = 256;

  while (new_header.flags & GEGL_FLAG_LOCKED)
    {
      g_usleep (50000);
      new_header = gegl_buffer_read_header (self->i, &offset)->header;
      self->foffset = 256;
    }

  if (new_header.rev == self->header.rev)
    {
      GEGL_NOTE(GEGL_DEBUG_TILE_BACKEND, "header not changed: %s", self->path);
      return;
    }
  else
    {
      self->header=new_header;
      GEGL_NOTE(GEGL_DEBUG_TILE_BACKEND, "loading index: %s", self->path);
    }

  tile_size = gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self));
  offset      = self->header.next;
  self->tiles = gegl_buffer_read_index (self->i, &offset);
  self->foffset = -1;
  backend     = GEGL_TILE_BACKEND (self);

  for (iter = self->tiles; iter; iter=iter->next)
    {
      GeglBufferItem *item = iter->data;

      GeglBufferItem *existing = g_hash_table_lookup (self->index, item);

      if (item->tile.offset > max)
        max = item->tile.offset + tile_size;

      if (existing)
        {
          if (existing->tile.rev == item->tile.rev)
            {
              g_assert (existing->tile.offset == item->tile.offset);
              existing->tile = item->tile;
              g_free (item);
              continue;
            }
          else
            {
              GeglTileStorage *storage =
                (void*)gegl_tile_backend_peek_storage (backend);
              GeglRectangle rect;
              g_hash_table_remove (self->index, existing);

              gegl_tile_source_refetch (GEGL_TILE_SOURCE (storage),
                                        existing->tile.x,
                                        existing->tile.y,
                                        existing->tile.z);

              if (existing->tile.z == 0)
                {
                  rect.width = self->header.tile_width;
                  rect.height = self->header.tile_height;
                  rect.x = existing->tile.x * self->header.tile_width;
                  rect.y = existing->tile.y * self->header.tile_height;
                }
              g_free (existing);

              g_signal_emit_by_name (storage, "changed", &rect, NULL);
            }
        }
      g_hash_table_insert (self->index, iter->data, iter->data);
    }
  g_list_free (self->tiles);
  g_slist_free (self->free_list);
  self->free_list      = NULL;
  self->next_pre_alloc = max; /* if bigger than own? */
  self->total          = max;
  self->tiles          = NULL;
}
static GObject *
gegl_tile_backend_file_constructor (GType                  type,
                                    guint                  n_params,
                                    GObjectConstructParam *params)
{
  GObject             *object;
  GeglTileBackendFile *self;
  GeglTileBackend     *backend;

  object  = G_OBJECT_CLASS (parent_class)->constructor (type, n_params, params);
  self    = GEGL_TILE_BACKEND_FILE (object);
  backend = GEGL_TILE_BACKEND (object);

  GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "constructing file backend: %s", self->path);
#if HAVE_GIO
  self->file = g_file_new_for_commandline_arg (self->path);
#else
  self->i = self->o = -1;
#endif
  self->index = g_hash_table_new (gegl_tile_backend_file_hashfunc, gegl_tile_backend_file_equalfunc);


  /* If the file already exists open it, assuming it is a GeglBuffer. */
#if HAVE_GIO
  if (g_file_query_exists (self->file, NULL))
#else
  if (access (self->path, F_OK) != -1)
#endif
    {
      goffset offset = 0;

#if HAVE_GIO
      /* Install a monitor for changes to the file in case other applications
       * might be writing to the buffer
       */
      self->monitor = g_file_monitor_file (self->file, G_FILE_MONITOR_NONE,
                                           NULL, NULL);
      g_signal_connect (self->monitor, "changed",
                        G_CALLBACK (gegl_tile_backend_file_file_changed),
                        self);

      {
        GError *error = NULL;
        self->io = G_IO_STREAM (g_file_open_readwrite (self->file, NULL, &error));
        if (error)
          {
            /* Try again but this time with only read access. This is
             * a quick-fix for make distcheck, where img_cmp fails
             * when it opens a GeglBuffer file in the source tree
             * (which is read-only).
             */
            g_error_free (error);
            error = NULL;
            self->i = G_INPUT_STREAM (g_file_read (self->file, NULL, &error));

            if (error)
              {
                g_warning ("%s: %s", G_STRLOC, error->message);
                g_error_free (error);
                error = NULL;
              }
          }
        else
          {
            self->o = g_io_stream_get_output_stream (self->io);
            self->i = g_io_stream_get_input_stream (self->io);
          }
      }

#else
      self->o = open (self->path, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
      self->i = dup (self->o);
#endif
      /*self->i = G_INPUT_STREAM (g_file_read (self->file, NULL, NULL));*/
      self->header = gegl_buffer_read_header (self->i, &offset)->header;
      self->header.rev = self->header.rev -1;

      /* we are overriding all of the work of the actual constructor here,
       * a really evil hack :d
       */
      backend->priv->tile_width = self->header.tile_width;
      backend->priv->tile_height = self->header.tile_height;
      backend->priv->format = babl_format (self->header.description);
      backend->priv->px_size = babl_format_get_bytes_per_pixel (backend->priv->format);
      backend->priv->tile_size = backend->priv->tile_width *
                                    backend->priv->tile_height *
                                    backend->priv->px_size;

      /* insert each of the entries into the hash table */
      gegl_tile_backend_file_load_index (self, TRUE);
      self->exist = TRUE;
#if HAVE_GIO
      /* We can only assert input stream, we won't have an output
       * stream on read-only files
       */
      g_assert (self->i);
#else
      g_assert (self->i != -1);
      g_assert (self->o != -1);
#endif

      /* to autoflush gegl_buffer_set */

      /* XXX: poking at internals, icky */
      backend->priv->shared = TRUE;
    }
  else
    {
      self->exist = FALSE; /* this is also the default, the file will be created on demand */
    }

#if HAVE_GIO
  g_assert (self->file);
#endif

  backend->priv->header = &self->header;

  return object;
}