diff options
author | Christophe Barbe <christophe@ufies.org> | 2002-08-14 18:55:10 +0000 |
---|---|---|
committer | Christophe Barbe <christophe@ufies.org> | 2002-08-14 18:55:10 +0000 |
commit | f18e69d8a685915be1243fb671af30d43c2d9eb5 (patch) | |
tree | b61f042b1ffd5757d92b9bdd08fd7e94b4945f10 /libgphoto2 | |
parent | 3eab8c56b1aafa201204f704f89077648ca60748 (diff) | |
download | libgphoto2-f18e69d8a685915be1243fb671af30d43c2d9eb5.tar.gz |
* Begining of a LRU implementation for the filesystem cache.
git-svn-id: https://svn.code.sf.net/p/gphoto/code/trunk/libgphoto2@5008 67ed7778-7388-44ab-90cf-0a291f65f57c
Diffstat (limited to 'libgphoto2')
-rw-r--r-- | libgphoto2/gphoto2-filesys.c | 251 |
1 files changed, 249 insertions, 2 deletions
diff --git a/libgphoto2/gphoto2-filesys.c b/libgphoto2/gphoto2-filesys.c index 0712f9ea0..84ae000b4 100644 --- a/libgphoto2/gphoto2-filesys.c +++ b/libgphoto2/gphoto2-filesys.c @@ -57,10 +57,12 @@ #define GP_MODULE "libgphoto2" -typedef struct { +typedef struct _CameraFilesystemFile { char name [128]; int info_dirty; CameraFileInfo info; + struct _CameraFilesystemFile *lru_prev; + struct _CameraFilesystemFile *lru_next; CameraFile *preview; CameraFile *normal; CameraFile *raw; @@ -175,6 +177,10 @@ struct _CameraFilesystem { int count; CameraFilesystemFolder *folder; + CameraFilesystemFile *lru_first; + CameraFilesystemFile *lru_last; + unsigned long int lru_size; + CameraFilesystemGetInfoFunc get_info_func; CameraFilesystemSetInfoFunc set_info_func; void *info_data; @@ -410,18 +416,23 @@ append_file (CameraFilesystem *fs, int x, CameraFile *file) return (GP_OK); } +static int gp_filesystem_lru_clear (CameraFilesystem *fs); + /** * gp_filesystem_reset: * @fs: a #CameraFilesystem * * Resets the filesystem. All cached information including the folder tree - * will get lost and will be queried again on demand. + * will get lost and will be queried again on demand. * * Return value: a gphoto2 error code. **/ int gp_filesystem_reset (CameraFilesystem *fs) { + + CR (gp_filesystem_lru_clear (fs)); + CR (delete_all_folders (fs, "/", NULL)); CR (delete_all_files (fs, 0)); @@ -1687,6 +1698,234 @@ gp_filesystem_get_info (CameraFilesystem *fs, const char *folder, return (GP_OK); } +static int +gp_filesystem_lru_clear (CameraFilesystem *fs) +{ + int n = 0; + CameraFilesystemFile *ptr, *prev; + + GP_DEBUG ("Clearing fscache LRU list..."); + + if (fs->lru_first == NULL) { + GP_DEBUG ("fscache LRU list already empty", n); + return (GP_OK); + } + + ptr = prev = fs->lru_first; + while (ptr != NULL) { + n++; + if (ptr->lru_prev != prev) { + GP_DEBUG ("fscache LRU list corrupted (%i)", n); + return (GP_ERROR); + } + prev = ptr; + ptr = ptr->lru_next; + + prev->lru_prev = NULL; + prev->lru_next = NULL; + } + + fs->lru_first = NULL; + fs->lru_last = NULL; + fs->lru_size = 0; + + GP_DEBUG ("fscache LRU list cleared (removed %i items)", n); + + return (GP_OK); +} + +static int +gp_filesystem_lru_remove_one (CameraFilesystem *fs, CameraFilesystemFile *item) +{ + if (item->lru_prev == NULL) { + return (GP_ERROR); + } + + if (fs->lru_last == item) { + if (fs->lru_first == item) { + + /* case 1 : ITEM is the only one in the list */ + + fs->lru_last = NULL; + fs->lru_first = NULL; + /* the list is now empty */ + } else { + + /* case 2 : ITEM is the last in the list */ + + fs->lru_last = item->lru_prev; + } + } else if (fs->lru_first == item) { + + /* case 3 : ITEM is the first in the list */ + + fs->lru_first = item->lru_next; + } else { + + /* case 4 : ITEM is in the middle of the list */ + + item->lru_prev->lru_next = item->lru_next; + } + + /* clear the pointers */ + item->lru_prev = NULL; + item->lru_next = NULL; + + return (GP_OK); +} + +static int +gp_filesystem_lru_free (CameraFilesystem *fs) +{ + CameraFilesystemFile *ptr; + const char *data; + unsigned long int size; + + CHECK_NULL (fs && fs->lru_first); + + ptr = fs->lru_first; + + GP_DEBUG ("Freeing cached data for file %s...", ptr->name); + + /* remove it from the list */ + fs->lru_first = ptr->lru_next; + if (fs->lru_first) { + fs->lru_first->lru_prev = fs->lru_first; + } else { + fs->lru_last = NULL; + } + + /* free its content */ + if (ptr->normal) { + CR( gp_file_get_data_and_size (ptr->normal, &data, &size)); + fs->lru_size -= size; + gp_file_unref (ptr->normal); + ptr->normal = NULL; + } + if (ptr->raw) { + CR( gp_file_get_data_and_size (ptr->raw, &data, &size)); + fs->lru_size -= size; + gp_file_unref (ptr->raw); + ptr->raw = NULL; + } + if (ptr->audio) { + CR( gp_file_get_data_and_size (ptr->audio, &data, &size)); + fs->lru_size -= size; + gp_file_unref (ptr->audio); + ptr->audio = NULL; + } + + return (GP_OK); + +} +static int + +gp_filesystem_lru_update (CameraFilesystem *fs, const char *folder, + CameraFile *file, GPContext *context) +{ + CameraFileType type; + CameraFile *oldfile; + const char *filename; + const char *data; + unsigned long int size; + int x, y; + + CHECK_NULL (fs && folder && file); + + CR (gp_file_get_name (file, &filename)); + CR (gp_file_get_type (file, &type)); + + CR( gp_file_get_data_and_size (file, &data, &size)); +/* The following is a simple case which is used to test the LRU */ +#if 0 + while (fs->lru_size + size > 600000) { + GP_DEBUG ("Freeing cached data before adding new data (cache=%ld, new=%ld)", + fs->lru_size, size); + CR (gp_filesystem_lru_free (fs)); + } +#endif + + GP_DEBUG ("Adding file '%s' from folder '%s' to the fscache LRU list (type %i)...", + filename, folder, type); + + /* Search folder and file */ + CR (x = gp_filesystem_folder_number (fs, folder, context)); + CR (y = gp_filesystem_number (fs, folder, filename, context)); + + /* if the file is already in the lru, we first remove it */ + if (fs->folder[x].file[y].lru_prev != NULL) { + + switch (type) { + case GP_FILE_TYPE_PREVIEW: oldfile = fs->folder[x].file[y].preview; break; + case GP_FILE_TYPE_NORMAL: oldfile = fs->folder[x].file[y].normal; break; + case GP_FILE_TYPE_RAW: oldfile = fs->folder[x].file[y].raw; break; + case GP_FILE_TYPE_AUDIO: oldfile = fs->folder[x].file[y].audio; break; + case GP_FILE_TYPE_EXIF: oldfile = fs->folder[x].file[y].exif; break; + default: + gp_context_error (context, _("Unknown file type %i."), type); + return (GP_ERROR); + } + if (oldfile) { + CR( gp_file_get_data_and_size (oldfile, &data, &size)); + fs->lru_size -= size; + } + + CR (gp_filesystem_lru_remove_one(fs, &fs->folder[x].file[y])); + } + + /* then add the file at the end of the LRU */ + if (fs->lru_first == NULL) { + fs->lru_first = &fs->folder[x].file[y]; + fs->lru_last = &fs->folder[x].file[y]; + /* for the first item, prev point it itself to show that the item + * is in the list */ + fs->folder[x].file[y].lru_prev = &fs->folder[x].file[y]; + } else { + fs->folder[x].file[y].lru_prev = fs->lru_last; + fs->lru_last->lru_next = &fs->folder[x].file[y]; + fs->lru_last = &fs->folder[x].file[y]; + } + + CR( gp_file_get_data_and_size (file, &data, &size)); + fs->lru_size += size; + + GP_DEBUG ("File '%s' from folder '%s' added in fscache LRU list.", + filename, folder); + + return (GP_OK); + +} + +static int +gp_filesystem_lru_check (CameraFilesystem *fs) +{ + int n=0; + CameraFilesystemFile *ptr, *prev; + + GP_DEBUG ("Checking fscache LRU list integrity..."); + + if (fs->lru_first == NULL) { + GP_DEBUG ("fscache LRU list empty", n); + return (GP_OK); + } + + ptr = prev = fs->lru_first; + while (ptr != NULL) { + n++; + if (ptr->lru_prev != prev) { + GP_DEBUG ("fscache LRU list corrupted (%i)", n); + return (GP_ERROR); + } + prev = ptr; + ptr = ptr->lru_next; + } + + GP_DEBUG ("fscache LRU list ok with %i items (%ld bytes)", n, fs->lru_size); + + return (GP_OK); + +} + /** * gp_filesystem_set_file_noop: * @fs: a #CameraFilesystem @@ -1727,6 +1966,14 @@ gp_filesystem_set_file_noop (CameraFilesystem *fs, const char *folder, CR (x = gp_filesystem_folder_number (fs, folder, context)); CR (y = gp_filesystem_number (fs, folder, filename, context)); + /* If we add a significant amount of data in the cache, we put (or + * move) a reference to this file in the LRU linked list. */ + if (!((type == GP_FILE_TYPE_PREVIEW) || (type == GP_FILE_TYPE_EXIF))) { + CR (gp_filesystem_lru_update (fs, folder, file, context)); + } + + CR (gp_filesystem_lru_check (fs)); + switch (type) { case GP_FILE_TYPE_PREVIEW: if (fs->folder[x].file[y].preview) |