static GeglTile * gegl_tile_backend_swap_get_tile (GeglTileSource *self, gint x, gint y, gint z) { GeglTileBackend *backend; GeglTileBackendSwap *tile_backend_swap; SwapEntry *entry; GeglTile *tile = NULL; gint tile_size; backend = GEGL_TILE_BACKEND (self); tile_backend_swap = GEGL_TILE_BACKEND_SWAP (backend); entry = gegl_tile_backend_swap_lookup_entry (tile_backend_swap, x, y, z); if (!entry) return NULL; tile_size = gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self)); tile = gegl_tile_new (tile_size); gegl_tile_mark_as_stored (tile); gegl_tile_backend_swap_entry_read (tile_backend_swap, entry, gegl_tile_get_data (tile)); return tile; }
/* this is the only place that actually should * instantiate tiles, when the cache is large enough * that should make sure we don't hit this function * too often. */ static GeglTile * gegl_tile_backend_file_get_tile (GeglTileSource *self, gint x, gint y, gint z) { GeglTileBackend *backend; GeglTileBackendFile *tile_backend_file; GeglBufferTile *entry; GeglTile *tile = NULL; gint tile_size; backend = GEGL_TILE_BACKEND (self); tile_backend_file = GEGL_TILE_BACKEND_FILE (backend); entry = gegl_tile_backend_file_lookup_entry (tile_backend_file, x, y, z); if (!entry) return NULL; tile_size = gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self)); tile = gegl_tile_new (tile_size); gegl_tile_set_rev (tile, entry->rev); gegl_tile_mark_as_stored (tile); gegl_tile_backend_file_file_entry_read (tile_backend_file, entry, gegl_tile_get_data (tile)); return tile; }
static void set_property (GObject *gobject, guint property_id, const GValue *value, GParamSpec *pspec) { GeglTileBackend *backend = GEGL_TILE_BACKEND (gobject); switch (property_id) { case PROP_TILE_WIDTH: backend->priv->tile_width = g_value_get_int (value); return; case PROP_TILE_HEIGHT: backend->priv->tile_height = g_value_get_int (value); return; case PROP_FORMAT: backend->priv->format = g_value_get_pointer (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, pspec); break; } }
static gpointer gegl_tile_backend_file_set_tile (GeglTileSource *self, GeglTile *tile, gint x, gint y, gint z) { GeglTileBackend *backend; GeglTileBackendFile *tile_backend_file; GeglBufferTile *entry; backend = GEGL_TILE_BACKEND (self); tile_backend_file = GEGL_TILE_BACKEND_FILE (backend); entry = gegl_tile_backend_file_lookup_entry (tile_backend_file, x, y, z); if (entry == NULL) { entry = gegl_tile_backend_file_file_entry_new (tile_backend_file); entry->x = x; entry->y = y; entry->z = z; g_hash_table_insert (tile_backend_file->index, entry, entry); } entry->rev = gegl_tile_get_rev (tile); gegl_tile_backend_file_file_entry_write (tile_backend_file, entry, gegl_tile_get_data (tile)); gegl_tile_mark_as_stored (tile); return NULL; }
static gpointer gegl_tile_backend_swap_set_tile (GeglTileSource *self, GeglTile *tile, gint x, gint y, gint z) { GeglTileBackend *backend; GeglTileBackendSwap *tile_backend_swap; SwapEntry *entry; backend = GEGL_TILE_BACKEND (self); tile_backend_swap = GEGL_TILE_BACKEND_SWAP (backend); entry = gegl_tile_backend_swap_lookup_entry (tile_backend_swap, x, y, z); gegl_tile_backend_swap_ensure_exist (); if (entry == NULL) { entry = gegl_tile_backend_swap_entry_create (x, y, z); entry->offset = gegl_tile_backend_swap_find_offset (gegl_tile_backend_get_tile_size (backend)); g_hash_table_insert (tile_backend_swap->index, entry, entry); } gegl_tile_backend_swap_entry_write (tile_backend_swap, entry, tile); gegl_tile_mark_as_stored (tile); return NULL; }
static void get_property (GObject *gobject, guint property_id, GValue *value, GParamSpec *pspec) { GeglTileBackend *backend = GEGL_TILE_BACKEND (gobject); switch (property_id) { case PROP_TILE_WIDTH: g_value_set_int (value, backend->priv->tile_width); break; case PROP_TILE_HEIGHT: g_value_set_int (value, backend->priv->tile_height); break; case PROP_TILE_SIZE: g_value_set_int (value, backend->priv->tile_size); break; case PROP_PX_SIZE: g_value_set_int (value, backend->priv->px_size); break; case PROP_FORMAT: g_value_set_pointer (value, (void*)backend->priv->format); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, pspec); break; } }
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 void constructed (GObject *object) { GeglTileBackend *backend = GEGL_TILE_BACKEND (object); G_OBJECT_CLASS (parent_class)->constructed (object); g_assert (backend->priv->tile_width > 0 && backend->priv->tile_height > 0); g_assert (backend->priv->format); 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; }
static void gegl_tile_backend_swap_constructed (GObject *object) { GeglTileBackend *backend = GEGL_TILE_BACKEND (object); G_OBJECT_CLASS (parent_class)->constructed (object); backend->priv->shared = FALSE; gegl_tile_backend_set_flush_on_destroy (backend, FALSE); GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "constructing swap backend"); }
static inline void gegl_tile_backend_file_file_entry_destroy (GeglBufferTile *entry, GeglTileBackendFile *self) { /* XXX: EEEk, throwing away bits */ guint offset = entry->offset; self->free_list = g_slist_prepend (self->free_list, GUINT_TO_POINTER (offset)); g_hash_table_remove (self->index, entry); gegl_tile_backend_file_dbg_dealloc (gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self))); g_free (entry); }
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 gpointer gegl_tile_backend_swap_exist_tile (GeglTileSource *self, GeglTile *tile, gint x, gint y, gint z) { GeglTileBackend *backend; GeglTileBackendSwap *tile_backend_swap; SwapEntry *entry; backend = GEGL_TILE_BACKEND (self); tile_backend_swap = GEGL_TILE_BACKEND_SWAP (backend); entry = gegl_tile_backend_swap_lookup_entry (tile_backend_swap, x, y, z); return entry!=NULL?((gpointer)0x1):NULL; }
static gpointer gegl_tile_backend_file_exist_tile (GeglTileSource *self, GeglTile *tile, gint x, gint y, gint z) { GeglTileBackend *backend; GeglTileBackendFile *tile_backend_file; GeglBufferTile *entry; backend = GEGL_TILE_BACKEND (self); tile_backend_file = GEGL_TILE_BACKEND_FILE (backend); entry = gegl_tile_backend_file_lookup_entry (tile_backend_file, x, y, z); return entry!=NULL?((gpointer)0x1):NULL; }
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 GObject * constructor (GType type, guint n_params, GObjectConstructParam *params) { GObject *object; GeglTileBackend *backend; object = G_OBJECT_CLASS (parent_class)->constructor (type, n_params, params); backend = GEGL_TILE_BACKEND (object); g_assert (backend->priv->tile_width > 0 && backend->priv->tile_height > 0); g_assert (backend->priv->format); 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; return object; }
static void gegl_tile_backend_swap_entry_write (GeglTileBackendSwap *self, SwapEntry *entry, guchar *source) { ThreadParams *params; gint length = gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self)); guchar *new_source; gegl_tile_backend_swap_ensure_exist (); if (entry->link) { g_mutex_lock (&mutex); if (entry->link) { params = entry->link->data; memcpy (params->source, source, length); g_mutex_unlock (&mutex); GEGL_NOTE(GEGL_DEBUG_TILE_BACKEND, "overwrote queue entry %i, %i, %i at %i", entry->x, entry->y, entry->z, (gint)entry->offset); return; } g_mutex_unlock (&mutex); } new_source = g_malloc (length); memcpy (new_source, source, length); params = g_slice_new0 (ThreadParams); params->operation = OP_WRITE; params->length = length; params->source = new_source; params->entry = entry; gegl_tile_backend_swap_push_queue (params); GEGL_NOTE(GEGL_DEBUG_TILE_BACKEND, "pushed write of entry %i, %i, %i at %i", entry->x, entry->y, entry->z, (gint)entry->offset); }
static GObject * gegl_tile_backend_swap_constructor (GType type, guint n_params, GObjectConstructParam *params) { GObject *object; GeglTileBackendSwap *self; GeglTileBackend *backend; object = G_OBJECT_CLASS (parent_class)->constructor (type, n_params, params); self = GEGL_TILE_BACKEND_SWAP (object); backend = GEGL_TILE_BACKEND (object); self->index = g_hash_table_new (gegl_tile_backend_swap_hashfunc, gegl_tile_backend_swap_equalfunc); backend->priv->shared = FALSE; GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "constructing swap backend"); return object; }
static void gegl_tile_backend_swap_entry_write (GeglTileBackendSwap *self, SwapEntry *entry, GeglTile *tile) { ThreadParams *params; gint length = gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self)); gegl_tile_backend_swap_ensure_exist (); if (entry->link) { g_mutex_lock (&mutex); if (entry->link) { params = entry->link->data; gegl_tile_unref (params->tile); params->tile = gegl_tile_dup (tile); g_mutex_unlock (&mutex); GEGL_NOTE(GEGL_DEBUG_TILE_BACKEND, "tile %i, %i, %i at %i is already enqueued, changed data", entry->x, entry->y, entry->z, (gint)entry->offset); return; } g_mutex_unlock (&mutex); } params = g_slice_new0 (ThreadParams); params->operation = OP_WRITE; params->length = length; params->tile = gegl_tile_dup (tile); params->entry = entry; gegl_tile_backend_swap_push_queue (params); GEGL_NOTE(GEGL_DEBUG_TILE_BACKEND, "pushed write of entry %i, %i, %i at %i", entry->x, entry->y, entry->z, (gint)entry->offset); }
static gpointer gegl_tile_backend_file_void_tile (GeglTileSource *self, GeglTile *tile, gint x, gint y, gint z) { GeglTileBackend *backend; GeglTileBackendFile *tile_backend_file; GeglBufferTile *entry; backend = GEGL_TILE_BACKEND (self); tile_backend_file = GEGL_TILE_BACKEND_FILE (backend); entry = gegl_tile_backend_file_lookup_entry (tile_backend_file, x, y, z); if (entry != NULL) { gegl_tile_backend_file_file_entry_destroy (entry, tile_backend_file); } return NULL; }
static void gegl_tile_backend_file_ensure_exist (GeglTileBackendFile *self) { if (!self->exist) { GeglTileBackend *backend; self->exist = TRUE; backend = GEGL_TILE_BACKEND (self); GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "creating swapfile %s", self->path); self->o = g_open (self->path, O_RDWR|O_CREAT, 0770); if (self->o == -1) g_warning ("%s: Could not open '%s': %s", G_STRFUNC, self->path, g_strerror (errno)); self->next_pre_alloc = 256; /* reserved space for header */ self->total = 256; /* reserved space for header */ self->foffset = 0; gegl_buffer_header_init (&self->header, backend->priv->tile_width, backend->priv->tile_height, backend->priv->px_size, backend->priv->format ); gegl_tile_backend_file_write_header (self); self->foffset = 256; fsync (self->o); self->i = dup (self->o); /*self->i = G_INPUT_STREAM (g_file_read (self->file, NULL, NULL));*/ self->next_pre_alloc = 256; /* reserved space for header */ self->total = 256; /* reserved space for header */ g_assert (self->i != -1); g_assert (self->o != -1); } }
static gpointer gegl_tile_backend_swap_void_tile (GeglTileSource *self, GeglTile *tile, gint x, gint y, gint z) { GeglTileBackend *backend; GeglTileBackendSwap *tile_backend_swap; SwapEntry *entry; backend = GEGL_TILE_BACKEND (self); tile_backend_swap = GEGL_TILE_BACKEND_SWAP (backend); entry = gegl_tile_backend_swap_lookup_entry (tile_backend_swap, x, y, z); if (entry != NULL) { GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "void tile %i, %i, %i", x, y, z); gegl_tile_backend_swap_entry_destroy (tile_backend_swap, entry); } return 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); 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_ensure_exist (GeglTileBackendFile *self) { if (!self->exist) { GeglTileBackend *backend; #if HAVE_GIO GError *error = NULL; if (self->io) { g_print ("we already existed\n"); return; } #endif self->exist = TRUE; backend = GEGL_TILE_BACKEND (self); GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "creating swapfile %s", self->path); #if HAVE_GIO self->o = G_OUTPUT_STREAM (g_file_replace (self->file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, NULL)); g_output_stream_flush (self->o, NULL, NULL); g_output_stream_close (self->o, NULL, NULL); self->io = G_IO_STREAM (g_file_open_readwrite (self->file, NULL, &error)); if (error) { g_warning ("%s: %s", G_STRLOC, error->message); g_error_free (error); error = NULL; } 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); #endif self->next_pre_alloc = 256; /* reserved space for header */ self->total = 256; /* reserved space for header */ #if HAVE_GIO g_assert(g_seekable_seek (G_SEEKABLE (self->o), 256, G_SEEK_SET, NULL, NULL)); #endif gegl_buffer_header_init (&self->header, backend->priv->tile_width, backend->priv->tile_height, backend->priv->px_size, backend->priv->format ); gegl_tile_backend_file_write_header (self); #if HAVE_GIO g_output_stream_flush (self->o, NULL, NULL); #else fsync (self->o); self->i = dup (self->o); #endif /*self->i = G_INPUT_STREAM (g_file_read (self->file, NULL, NULL));*/ self->next_pre_alloc = 256; /* reserved space for header */ self->total = 256; /* reserved space for header */ #if HAVE_GIO g_assert (self->io); g_assert (self->i); g_assert (self->o); #else g_assert (self->i != -1); g_assert (self->o != -1); #endif } }
static void gegl_tile_backend_swap_entry_destroy (GeglTileBackendSwap *self, SwapEntry *entry) { guint64 start, end; gint tile_size = gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self)); GList *hlink; if (entry->link) { GList *link; g_mutex_lock (&mutex); if ((link = entry->link)) { ThreadParams *queued_op = link->data; g_queue_delete_link (queue, link); gegl_tile_unref (queued_op->tile); g_slice_free (ThreadParams, queued_op); } g_mutex_unlock (&mutex); } start = entry->offset; end = start + tile_size; if ((hlink = gap_list)) while (hlink) { GList *llink = hlink->prev; SwapGap *lgap, *hgap; if (llink) lgap = llink->data; hgap = hlink->data; /* attempt to merge lower, upper and this gap */ if (llink != NULL && lgap->end == start && hgap->start == end) { llink->next = hlink->next; if (hlink->next) hlink->next->prev = llink; lgap->end = hgap->end; g_slice_free (SwapGap, hgap); hlink->next = NULL; hlink->prev = NULL; g_list_free (hlink); break; } /* attempt to merge with upper gap */ else if (hgap->start == end) { hgap->start = start; break; } /* attempt to merge with lower gap */ else if (llink != NULL && lgap->end == start) { lgap->end = end; break; } /* create new gap */ else if (hgap->start > end) { lgap = gegl_tile_backend_swap_gap_new (start, end); gap_list = g_list_insert_before (gap_list, hlink, lgap); break; } /* if there's no more elements in the list after this */ else if (hlink->next == NULL) { /* attempt to merge with the last gap */ if (hgap->end == start) { hgap->end = end; } /* create a new gap in the end of the list */ else { GList *new_link; hgap = gegl_tile_backend_swap_gap_new (start, end); new_link = g_list_alloc (); new_link->next = NULL; new_link->prev = hlink; new_link->data = hgap; hlink->next = new_link; } break; } hlink = hlink->next; } else gap_list = g_list_prepend (NULL, gegl_tile_backend_swap_gap_new (start, end)); g_hash_table_remove (self->index, entry); g_slice_free (SwapEntry, entry); }
static void gegl_tile_backend_swap_entry_read (GeglTileBackendSwap *self, SwapEntry *entry, guchar *dest) { gint tile_size = gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self)); gint to_be_read = tile_size; guint64 offset = entry->offset; gegl_tile_backend_swap_ensure_exist (); if (entry->link || in_progress) { ThreadParams *queued_op = NULL; g_mutex_lock (&mutex); if (entry->link) queued_op = entry->link->data; else if (in_progress && in_progress->entry == entry) queued_op = in_progress; if (queued_op) { memcpy (dest, gegl_tile_get_data (queued_op->tile), to_be_read); g_mutex_unlock (&mutex); GEGL_NOTE(GEGL_DEBUG_TILE_BACKEND, "read entry %i, %i, %i from queue", entry->x, entry->y, entry->z); return; } g_mutex_unlock (&mutex); } if (in_offset != offset) { if (lseek (in_fd, offset, SEEK_SET) < 0) { g_warning ("unable to seek to tile in buffer: %s", g_strerror (errno)); return; } in_offset = offset; } while (to_be_read > 0) { GError *error = NULL; gint byte_read; byte_read = read (in_fd, dest + tile_size - to_be_read, to_be_read); if (byte_read <= 0) { g_message ("unable to read tile data from swap: " "%s (%d/%d bytes read) %s", g_strerror (errno), byte_read, to_be_read, error?error->message:"--"); return; } to_be_read -= byte_read; in_offset += byte_read; } GEGL_NOTE(GEGL_DEBUG_TILE_BACKEND, "read entry %i, %i, %i from %i", entry->x, entry->y, entry->z, (gint)offset); }
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; }
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; }