Mercurial > geeqie
view src/filecache.c @ 1766:6e0f6d5e4c25
added a workaround for https://bugzilla.gnome.org/show_bug.cgi?id=590692
author | nadvornik |
---|---|
date | Sat, 10 Oct 2009 15:01:41 +0000 |
parents | 5f49f305a6b6 |
children | 956aab097ea7 |
line wrap: on
line source
/* * Geeqie * Copyright (C) 2008 - 2009 The Geeqie Team * * Author: Vladimir Nadvornik * * This software is released under the GNU General Public License (GNU GPL). * Please read the included file COPYING for more information. * This software comes with no warranty of any kind, use at your own risk! */ #include "main.h" #include "filecache.h" /* Set to TRUE to add file cache dumps to the debug output */ const gboolean debug_file_cache = FALSE; /* this implements a simple LRU algorithm */ struct _FileCacheData { FileCacheReleaseFunc release; GList *list; gulong max_size; gulong size; }; typedef struct _FileCacheEntry FileCacheEntry; struct _FileCacheEntry { FileData *fd; gulong size; }; static void file_cache_notify_cb(FileData *fd, NotifyType type, gpointer data); FileCacheData *file_cache_new(FileCacheReleaseFunc release, gulong max_size) { FileCacheData *fc = g_new(FileCacheData, 1); fc->release = release; fc->list = NULL; fc->max_size = max_size; fc->size = 0; file_data_register_notify_func(file_cache_notify_cb, fc, NOTIFY_PRIORITY_HIGH); return fc; } gboolean file_cache_get(FileCacheData *fc, FileData *fd) { GList *work; g_assert(fc && fd); work = fc->list; while (work) { FileCacheEntry *fce = work->data; if (fce->fd == fd) { /* entry exists */ DEBUG_2("cache hit: fc=%p %s", fc, fd->path); if (work == fc->list) return TRUE; /* already at the beginning */ /* move it to the beginning */ DEBUG_2("cache move to front: fc=%p %s", fc, fd->path); fc->list = g_list_remove_link(fc->list, work); fc->list = g_list_concat(work, fc->list); if (file_data_check_changed_files(fd)) /* this will eventually remove changed files from cache via file_cache_notify_cb */ return FALSE; if (debug_file_cache) file_cache_dump(fc); return TRUE; } work = work->next; } DEBUG_2("cache miss: fc=%p %s", fc, fd->path); return FALSE; } void file_cache_set_size(FileCacheData *fc, gulong size) { GList *work; FileCacheEntry *last_fe; if (debug_file_cache) file_cache_dump(fc); work = g_list_last(fc->list); while (fc->size > size && work) { GList *prev; last_fe = work->data; prev = work->prev; fc->list = g_list_delete_link(fc->list, work); work = prev; DEBUG_2("file changed - cache remove: fc=%p %s", fc, last_fe->fd->path); fc->size -= last_fe->size; fc->release(last_fe->fd); file_data_unref(last_fe->fd); g_free(last_fe); } } void file_cache_put(FileCacheData *fc, FileData *fd, gulong size) { FileCacheEntry *fe; if (file_cache_get(fc, fd)) return; DEBUG_2("cache add: fc=%p %s", fc, fd->path); fe = g_new(FileCacheEntry, 1); fe->fd = file_data_ref(fd); fe->size = size; fc->list = g_list_prepend(fc->list, fe); fc->size += size; file_cache_set_size(fc, fc->max_size); } gulong file_cache_get_max_size(FileCacheData *fc) { return fc->max_size; } gulong file_cache_get_size(FileCacheData *fc) { return fc->size; } void file_cache_set_max_size(FileCacheData *fc, gulong size) { fc->max_size = size; file_cache_set_size(fc, fc->max_size); } static void file_cache_remove_fd(FileCacheData *fc, FileData *fd) { GList *work; FileCacheEntry *fe; if (debug_file_cache) file_cache_dump(fc); work = fc->list; while (work) { GList *current = work; fe = work->data; work = work->next; if (fe->fd == fd) { fc->list = g_list_delete_link(fc->list, current); DEBUG_1("cache remove: fc=%p %s", fc, fe->fd->path); fc->size -= fe->size; fc->release(fe->fd); file_data_unref(fe->fd); g_free(fe); } } } void file_cache_dump(FileCacheData *fc) { GList *work = fc->list; gulong n = 0; DEBUG_1("cache dump: fc=%p max size:%ld size:%ld", fc, fc->max_size, fc->size); while (work) { FileCacheEntry *fe = work->data; work = work->next; DEBUG_1("cache entry: fc=%p [%lu] %s %ld", fc, ++n, fe->fd->path, fe->size); } } static void file_cache_notify_cb(FileData *fd, NotifyType type, gpointer data) { FileCacheData *fc = data; if (type & (NOTIFY_REREAD | NOTIFY_CHANGE)) /* invalidate the entry on each file change */ { DEBUG_1("Notify cache: %s %04x", fd->path, type); file_cache_remove_fd(fc, fd); } } /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */