Optimize file_cache_get() by only moving element to front if needed
[geeqie.git] / src / filecache.c
1 /*
2  * Geeqie
3  * Copyright (C) 2008 The Geeqie Team
4  *
5  * Author: Vladimir Nadvornik
6  *
7  * This software is released under the GNU General Public License (GNU GPL).
8  * Please read the included file COPYING for more information.
9  * This software comes with no warranty of any kind, use at your own risk!
10  */
11
12
13 #include "main.h"
14 #include "filecache.h"
15
16 /* Set to TRUE to add file cache dumps to the debug output */
17 const gboolean debug_file_cache = FALSE;
18
19 /* this implements a simple LRU algorithm */
20
21 struct _FileCacheData {
22         FileCacheReleaseFunc release;
23         GList *list;
24         gulong max_size;
25         gulong size;
26         };
27
28 typedef struct _FileCacheEntry FileCacheEntry;
29 struct _FileCacheEntry {
30         FileData *fd;
31         gulong size;
32         };
33
34 FileCacheData *file_cache_new(FileCacheReleaseFunc release, gulong max_size)
35 {
36         FileCacheData *fc = g_new(FileCacheData, 1);
37         fc->release = release;
38         fc->list = NULL;
39         fc->max_size = max_size;
40         fc->size = 0;
41         return fc;
42 }
43
44 gboolean file_cache_get(FileCacheData *fc, FileData *fd)
45 {
46         GList *work;
47         
48         g_assert(fc && fd);
49
50         work = fc->list;
51         while (work)
52                 {
53                 FileCacheEntry *fce = work->data;
54                 if (fce->fd == fd)
55                         {
56                         /* entry exists */
57                         DEBUG_1("cache hit: fc=%p %s", fc, fd->path);
58                         if (work == fc->list) return TRUE; /* already at the beginning */
59                         /* move it to the beginning */
60                         DEBUG_1("cache move to front: fc=%p %s", fc, fd->path);
61                         fc->list = g_list_remove_link(fc->list, work);
62                         fc->list = g_list_concat(work, fc->list);
63                         if (debug_file_cache) file_cache_dump(fc);
64                         return TRUE;
65                         }
66                 work = work->next;
67                 }
68         DEBUG_1("cache miss: fc=%p %s", fc, fd->path);
69         return FALSE;
70 }
71
72 void file_cache_set_size(FileCacheData *fc, gulong size)
73 {
74         GList *work;
75         FileCacheEntry *last_fe;
76
77         if (debug_file_cache) file_cache_dump(fc);
78
79         work = g_list_last(fc->list);
80         while (fc->size > size && work)
81                 {
82                 GList *prev;
83                 last_fe = work->data;
84                 prev = work->prev; 
85                 fc->list = g_list_delete_link(fc->list, work);
86                 work = prev;
87                 
88                 DEBUG_1("cache remove: fc=%p %s", fc, last_fe->fd->path);
89                 fc->size -= last_fe->size;
90                 fc->release(last_fe->fd);
91                 file_data_unref(last_fe->fd);
92                 g_free(last_fe);
93                 }
94 }
95
96 void file_cache_put(FileCacheData *fc, FileData *fd, gulong size)
97 {
98         FileCacheEntry *fe;
99
100         if (file_cache_get(fc, fd)) return;
101         
102         DEBUG_1("cache add: fc=%p %s", fc, fd->path);
103         fe = g_new(FileCacheEntry, 1);
104         fe->fd = file_data_ref(fd);
105         fe->size = size;
106         fc->list = g_list_prepend(fc->list, fe);
107         fc->size += size;
108         
109         file_cache_set_size(fc, fc->max_size);
110 }
111
112 gulong file_cache_get_max_size(FileCacheData *fc)
113 {
114         return fc->max_size;
115 }
116
117 gulong file_cache_get_size(FileCacheData *fc)
118 {
119         return fc->size;
120 }
121
122 void file_cache_set_max_size(FileCacheData *fc, gulong size)
123 {
124         fc->max_size = size;
125         file_cache_set_size(fc, fc->max_size);
126 }
127
128 void file_cache_dump(FileCacheData *fc)
129 {
130         GList *work;
131         work = fc->list;
132         guint n = 0;
133         DEBUG_1("cache dump: fc=%p max size:%ld size:%ld", fc, fc->max_size, fc->size);
134                 
135         while (work)
136                 {
137                 FileCacheEntry *fe = work->data;
138                 work = work->next;
139                 DEBUG_1("cache entry: fc=%p [%lu] %s %ld", fc, ++n, fe->fd->path, fe->size);
140                 }
141 }