summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNaïm Favier <n@monade.li>2024-06-02 15:31:33 +0200
committerBirte Friesel <derf@chaosdorf.de>2024-06-30 11:40:06 +0200
commit08b269d172acc2b4cb9b9336e2cd8097d89ef6a7 (patch)
treeece7aca6a7eccf8ca37b863b6ce2dd6f4abf2402
parent186dab662b50e7aa1e15674c468d35810a691409 (diff)
cache stat(2) calls
When the user requests sorting by size or mtime, do a "soft preload" of the file list that only calls stat(2) without loading images. This avoids calling stat(2) repeatedly on the same files when sorting the file list, and achieves faster startup on slow filesystems.
-rw-r--r--src/filelist.c95
-rw-r--r--src/filelist.h10
-rw-r--r--src/list.c2
-rw-r--r--src/menu.c4
-rw-r--r--src/slideshow.c8
5 files changed, 67 insertions, 52 deletions
diff --git a/src/filelist.c b/src/filelist.c
index f1e820c..a5ad890 100644
--- a/src/filelist.c
+++ b/src/filelist.c
@@ -53,6 +53,8 @@ feh_file *feh_file_new(char *filename)
newfile->name = estrdup(s + 1);
else
newfile->name = estrdup(filename);
+ newfile->size = -1;
+ newfile->mtime = 0;
newfile->info = NULL;
#ifdef HAVE_LIBEXIF
newfile->ed = NULL;
@@ -89,7 +91,6 @@ feh_file_info *feh_file_info_new(void)
info->width = 0;
info->height = 0;
- info->size = 0;
info->pixels = 0;
info->has_alpha = 0;
info->format = NULL;
@@ -305,7 +306,7 @@ void delete_rm_files(void)
return;
}
-gib_list *feh_file_info_preload(gib_list * list)
+gib_list *feh_file_info_preload(gib_list * list, int load_images)
{
gib_list *l;
feh_file *file = NULL;
@@ -314,20 +315,27 @@ gib_list *feh_file_info_preload(gib_list * list)
for (l = list; l; l = l->next) {
file = FEH_FILE(l->data);
D(("file %p, file->next %p, file->name %s\n", l, l->next, file->name));
- if (feh_file_info_load(file, NULL)) {
- D(("Failed to load file %p\n", file));
- remove_list = gib_list_add_front(remove_list, l);
- if (opt.verbose)
- feh_display_status('x');
- } else if (((unsigned int)file->info->width < opt.min_width)
- || ((unsigned int)file->info->width > opt.max_width)
- || ((unsigned int)file->info->height < opt.min_height)
- || ((unsigned int)file->info->height > opt.max_height)) {
- remove_list = gib_list_add_front(remove_list, l);
- if (opt.verbose)
- feh_display_status('s');
- } else if (opt.verbose)
- feh_display_status('.');
+ if (load_images) {
+ if (feh_file_info_load(file, NULL)) {
+ D(("Failed to load file %p\n", file));
+ remove_list = gib_list_add_front(remove_list, l);
+ if (opt.verbose)
+ feh_display_status('x');
+ } else if (((unsigned int)file->info->width < opt.min_width)
+ || ((unsigned int)file->info->width > opt.max_width)
+ || ((unsigned int)file->info->height < opt.min_height)
+ || ((unsigned int)file->info->height > opt.max_height)) {
+ remove_list = gib_list_add_front(remove_list, l);
+ if (opt.verbose)
+ feh_display_status('s');
+ } else if (opt.verbose)
+ feh_display_status('.');
+ } else {
+ if (feh_file_stat(file)) {
+ D(("Failed to stat file %p\n", file));
+ remove_list = gib_list_add_front(remove_list, l);
+ }
+ }
if (sig_exit) {
feh_display_status(0);
exit(sig_exit);
@@ -348,23 +356,36 @@ gib_list *feh_file_info_preload(gib_list * list)
return(list);
}
-int feh_file_info_load(feh_file * file, Imlib_Image im)
+int feh_file_stat(feh_file * file)
{
struct stat st;
+
+ errno = 0;
+ if (stat(file->filename, &st)) {
+ feh_print_stat_error(file->filename);
+ return(1);
+ }
+
+ file->mtime = st.st_mtime;
+
+ file->size = st.st_size;
+
+ return(0);
+}
+
+int feh_file_info_load(feh_file * file, Imlib_Image im)
+{
int need_free = 1;
Imlib_Image im1;
+ if (feh_file_stat(file))
+ return(1);
+
D(("im is %p\n", im));
if (im)
need_free = 0;
- errno = 0;
- if (stat(file->filename, &st)) {
- feh_print_stat_error(file->filename);
- return(1);
- }
-
if (im)
im1 = im;
else if (!feh_load_image(&im1, file) || !im1)
@@ -381,8 +402,6 @@ int feh_file_info_load(feh_file * file, Imlib_Image im)
file->info->format = estrdup(gib_imlib_image_format(im1));
- file->info->size = st.st_size;
-
if (need_free)
gib_imlib_free_image_and_decache(im1);
return(0);
@@ -434,20 +453,8 @@ int feh_cmp_dirname(void *file1, void *file2)
/* Return -1 if file1 is _newer_ than file2 */
int feh_cmp_mtime(void *file1, void *file2)
{
- struct stat s1, s2;
-
- if (stat(FEH_FILE(file1)->filename, &s1)) {
- feh_print_stat_error(FEH_FILE(file1)->filename);
- return(-1);
- }
-
- if (stat(FEH_FILE(file2)->filename, &s2)) {
- feh_print_stat_error(FEH_FILE(file2)->filename);
- return(-1);
- }
-
/* gib_list_sort is not stable, so explicitly return 0 as -1 */
- return(s1.st_mtime >= s2.st_mtime ? -1 : 1);
+ return(FEH_FILE(file1)->mtime >= FEH_FILE(file2)->mtime ? -1 : 1);
}
int feh_cmp_width(void *file1, void *file2)
@@ -467,7 +474,7 @@ int feh_cmp_pixels(void *file1, void *file2)
int feh_cmp_size(void *file1, void *file2)
{
- return((FEH_FILE(file1)->info->size - FEH_FILE(file2)->info->size));
+ return((FEH_FILE(file1)->size - FEH_FILE(file2)->size));
}
int feh_cmp_format(void *file1, void *file2)
@@ -486,10 +493,16 @@ void feh_prepare_filelist(void)
* is set and we're in thumbnail mode, we need to filter images first so
* we can create a properly sized thumbnail list.
*/
- if (opt.list || opt.preload || opt.customlist || (opt.sort > SORT_MTIME)
+ if (opt.list || opt.preload || opt.customlist || (opt.sort >= SORT_WIDTH)
|| (opt.filter_by_dimensions && (opt.index || opt.thumbs || opt.bgmode))) {
/* For these sort options, we have to preload images */
- filelist = feh_file_info_preload(filelist);
+ filelist = feh_file_info_preload(filelist, TRUE);
+ if (!gib_list_length(filelist))
+ show_mini_usage();
+ } else if (opt.sort >= SORT_SIZE) {
+ /* For these sort options, we need stat(2) information on the files,
+ * but there is no need to load the images. */
+ filelist = feh_file_info_preload(filelist, FALSE);
if (!gib_list_length(filelist))
show_mini_usage();
}
diff --git a/src/filelist.h b/src/filelist.h
index 7f263dc..e648262 100644
--- a/src/filelist.h
+++ b/src/filelist.h
@@ -36,6 +36,8 @@ struct __feh_file {
char *name;
/* info stuff */
+ time_t mtime;
+ int size;
feh_file_info *info; /* only set when needed */
#ifdef HAVE_LIBEXIF
ExifData *ed;
@@ -45,7 +47,6 @@ struct __feh_file {
struct __feh_file_info {
int width;
int height;
- int size;
int pixels;
unsigned char has_alpha;
char *format;
@@ -71,11 +72,11 @@ enum sort_type {
SORT_NAME,
SORT_FILENAME,
SORT_DIRNAME,
+ SORT_SIZE, // everything after SORT_SIZE requires stat(2) information on the filelist
SORT_MTIME,
- SORT_WIDTH,
+ SORT_WIDTH, // everything after SORT_WIDTH requires preloading the images in the filelist
SORT_HEIGHT,
SORT_PIXELS,
- SORT_SIZE,
SORT_FORMAT
};
@@ -88,7 +89,8 @@ int file_selector_all(const struct dirent *unused);
void add_file_to_filelist_recursively(char *origpath, unsigned char level);
void add_file_to_rm_filelist(char *file);
void delete_rm_files(void);
-gib_list *feh_file_info_preload(gib_list * list);
+gib_list *feh_file_info_preload(gib_list * list, int load_images);
+int feh_file_stat(feh_file * file);
int feh_file_info_load(feh_file * file, Imlib_Image im);
void feh_file_dirname(char *dst, feh_file * f, int maxlen);
void feh_prepare_filelist(void);
diff --git a/src/list.c b/src/list.c
index f293af3..0ef31ea 100644
--- a/src/list.c
+++ b/src/list.c
@@ -50,7 +50,7 @@ void init_list_mode(void)
file->info->height,
format_size(file->info->pixels));
printf("\t%s\t%c\t%s\n",
- format_size(file->info->size),
+ format_size(file->size),
file->info->has_alpha ? 'X' : '-', file->filename);
}
diff --git a/src/menu.c b/src/menu.c
index b1ef61d..9c20692 100644
--- a/src/menu.c
+++ b/src/menu.c
@@ -835,7 +835,7 @@ void feh_menu_draw_submenu_at(int x, int y, Imlib_Image dst, int ox, int oy)
for (int i= 0; i <= 3; i++) {
imlib_image_draw_line(x+i, y+3+i, x+i, y+9-i, 0);
}
-
+
return;
}
@@ -1401,7 +1401,7 @@ static feh_menu *feh_menu_func_gen_info(feh_menu * m)
if (!file->info)
feh_file_info_load(file, im);
if (file->info) {
- snprintf(buffer, sizeof(buffer), "Size: %dKb", file->info->size / 1024);
+ snprintf(buffer, sizeof(buffer), "Size: %dKb", file->size / 1024);
feh_menu_add_entry(mm, buffer, NULL, 0, 0, NULL);
snprintf(buffer, sizeof(buffer), "Dimensions: %dx%d", file->info->width, file->info->height);
feh_menu_add_entry(mm, buffer, NULL, 0, 0, NULL);
diff --git a/src/slideshow.c b/src/slideshow.c
index a53749e..3944a68 100644
--- a/src/slideshow.c
+++ b/src/slideshow.c
@@ -496,14 +496,14 @@ char *feh_printf(char *str, feh_file * file, winwidget winwid)
}
break;
case 's':
- if (file && (file->info || !feh_file_info_load(file, NULL))) {
- snprintf(buf, sizeof(buf), "%d", file->info->size);
+ if (file && (file->size >= 0 || !feh_file_stat(file))) {
+ snprintf(buf, sizeof(buf), "%d", file->size);
strncat(ret, buf, sizeof(ret) - strlen(ret) - 1);
}
break;
case 'S':
- if (file && (file->info || !feh_file_info_load(file, NULL))) {
- strncat(ret, format_size(file->info->size), sizeof(ret) - strlen(ret) - 1);
+ if (file && (file->size >= 0 || !feh_file_stat(file))) {
+ strncat(ret, format_size(file->size), sizeof(ret) - strlen(ret) - 1);
}
break;
case 't':