[evince/wip/hadess/faster-libarchive: 3/3] comics: Speed up fetching page sizes




commit 7f656852882f2016f7ea0089cc5d4dd06cf63a97
Author: Bastien Nocera <hadess hadess net>
Date:   Sat Feb 26 13:06:43 2022 +0100

    comics: Speed up fetching page sizes
    
    Significantly speed up fetching page sizes by keeping track of which
    order the files are inside the archive.
    
    Before this patch, the code would always open the archive again, loop
    until we got to the page of interest, decode enough of it to fetch the
    sizes, and close the archive.
    
    As libarchive cannot reset, but can skip forward pretty fast, don't
    reset the archive each time, and use the old instance as long as the
    next page of interest is placed later in the archive.
    
    On a 200 pages CB7 file, this cut down the page size detection from 2
    minutes 15 seconds to 3 seconds.

 backend/comics/comics-document.c | 64 ++++++++++++++++++++++++++++++++--------
 1 file changed, 51 insertions(+), 13 deletions(-)
---
diff --git a/backend/comics/comics-document.c b/backend/comics/comics-document.c
index 167e11f26..1f2a22a1d 100644
--- a/backend/comics/comics-document.c
+++ b/backend/comics/comics-document.c
@@ -52,6 +52,7 @@ struct _ComicsDocument
        gchar         *archive_path;
        gchar         *archive_uri;
        GPtrArray     *page_names; /* elem: char * */
+       GHashTable    *page_positions; /* key: char *, value: uint + 1 */
 };
 
 EV_BACKEND_REGISTER (ComicsDocument, comics_document)
@@ -143,6 +144,32 @@ is_apple_double (const char *name)
        return ret;
 }
 
+static gboolean
+archive_reopen_if_needed (ComicsDocument  *comics_document,
+                         const char      *page_wanted,
+                         GError         **error)
+{
+       const char *current_page;
+       guint current_page_idx, page_wanted_idx;
+
+       if (ev_archive_at_entry (comics_document->archive)) {
+               current_page = ev_archive_get_entry_pathname (comics_document->archive);
+               if (current_page) {
+                       current_page_idx = GPOINTER_TO_UINT (g_hash_table_lookup 
(comics_document->page_positions, current_page));
+                       page_wanted_idx = GPOINTER_TO_UINT (g_hash_table_lookup 
(comics_document->page_positions, page_wanted));
+
+                       if (current_page_idx != 0 &&
+                           page_wanted_idx != 0 &&
+                           page_wanted_idx > current_page_idx)
+                               return TRUE;
+               }
+
+               ev_archive_reset (comics_document->archive);
+       }
+
+       return ev_archive_open_filename (comics_document->archive, comics_document->archive_path, error);
+}
+
 static GPtrArray *
 comics_document_list (ComicsDocument  *comics_document,
                      GError         **error)
@@ -246,6 +273,18 @@ out:
        return array;
 }
 
+static GHashTable *
+save_positions (GPtrArray *page_names)
+{
+       guint i;
+       GHashTable *ht;
+
+       ht = g_hash_table_new (g_str_hash, g_str_equal);
+       for (i = 0; i < page_names->len; i++)
+               g_hash_table_insert (ht, page_names->pdata[i], GUINT_TO_POINTER(i + 1));
+       return ht;
+}
+
 /* This function chooses the archive decompression support
  * book based on its mime type. */
 static gboolean
@@ -341,6 +380,9 @@ comics_document_load (EvDocument *document,
        if (!comics_document->page_names)
                return FALSE;
 
+       /* Keep an index */
+       comics_document->page_positions = save_positions (comics_document->page_names);
+
         /* Now sort the pages */
         g_ptr_array_sort (comics_document->page_names, sort_page_names);
 
@@ -397,10 +439,12 @@ comics_document_get_page_size (EvDocument *document,
        PixbufInfo info;
        GError *error = NULL;
 
-       if (!ev_archive_open_filename (comics_document->archive, comics_document->archive_path, &error)) {
+       page_path = g_ptr_array_index (comics_document->page_names, page->index);
+
+       if (!archive_reopen_if_needed (comics_document, page_path, &error)) {
                g_warning ("Fatal error opening archive: %s", error->message);
                g_error_free (error);
-               goto out;
+               return;
        }
 
        loader = gdk_pixbuf_loader_new ();
@@ -409,8 +453,6 @@ comics_document_get_page_size (EvDocument *document,
                          G_CALLBACK (get_page_size_prepared_cb),
                          &info);
 
-       page_path = g_ptr_array_index (comics_document->page_names, page->index);
-
        while (1) {
                const char *name;
                GError *error = NULL;
@@ -458,9 +500,6 @@ comics_document_get_page_size (EvDocument *document,
                if (height)
                        *height = info.height;
        }
-
-out:
-       ev_archive_reset (comics_document->archive);
 }
 
 static void
@@ -486,10 +525,12 @@ comics_document_render_pixbuf (EvDocument      *document,
        const char *page_path;
        GError *error = NULL;
 
-       if (!ev_archive_open_filename (comics_document->archive, comics_document->archive_path, &error)) {
+       page_path = g_ptr_array_index (comics_document->page_names, rc->page->index);
+
+       if (!archive_reopen_if_needed (comics_document, page_path, &error)) {
                g_warning ("Fatal error opening archive: %s", error->message);
                g_error_free (error);
-               goto out;
+               return NULL;
        }
 
        loader = gdk_pixbuf_loader_new ();
@@ -497,8 +538,6 @@ comics_document_render_pixbuf (EvDocument      *document,
                          G_CALLBACK (render_pixbuf_size_prepared_cb),
                          rc);
 
-       page_path = g_ptr_array_index (comics_document->page_names, rc->page->index);
-
        while (1) {
                const char *name;
 
@@ -544,8 +583,6 @@ comics_document_render_pixbuf (EvDocument      *document,
        }
        g_object_unref (loader);
 
-out:
-       ev_archive_reset (comics_document->archive);
        return rotated_pixbuf;
 }
 
@@ -573,6 +610,7 @@ comics_document_finalize (GObject *object)
                 g_ptr_array_free (comics_document->page_names, TRUE);
        }
 
+       g_clear_pointer (&comics_document->page_positions, g_hash_table_destroy);
        g_clear_object (&comics_document->archive);
        g_free (comics_document->archive_path);
        g_free (comics_document->archive_uri);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]