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 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 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 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 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; }