[libgit2-glib: 1/3] diff: Cache object by content, not location



commit 8433c18e4284890bf34f4c4829df3fd7f9bfe530
Author: Martin Blanchard <tchaik gmx com>
Date:   Mon Jan 22 15:57:53 2018 +0100

    diff: Cache object by content, not location
    
    Diff objects (deltas and hunks) from libgit2 are cached in a hash
    table, using object's memory locations as keys. In some cases,
    libgit2 does not generate new delta and hunk objects but simply
    modify its first allocated struct in place. git_diff_blob_to_buffer()
    function does so for hunks, for example, thus breaking the memory
    location based index logic of libgit2-glib.
    
    This patch makes the index logic rely on actual object's content
    instead of memory location. Index for deltas are generated from
    'old_file' git oid. Index for hunks are generated from a combination
    of its belonging delta's 'old_file' git oid and its own header.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=792733
    https://gitlab.gnome.org/GNOME/gitg/issues/109

 libgit2-glib/ggit-diff.c | 57 ++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 48 insertions(+), 9 deletions(-)
---
diff --git a/libgit2-glib/ggit-diff.c b/libgit2-glib/ggit-diff.c
index 640d946..83e1303 100644
--- a/libgit2-glib/ggit-diff.c
+++ b/libgit2-glib/ggit-diff.c
@@ -76,18 +76,36 @@ wrap_diff_delta_cached (CallbackWrapperData  *data,
                         const git_diff_delta *delta)
 {
        GgitDiffDelta *gdelta;
+       gchar *key;
 
        if (!delta)
        {
                return NULL;
        }
 
-       gdelta = g_hash_table_lookup (data->cached_deltas, delta);
+       if (delta->old_file.path != NULL)
+       {
+               key = g_strdup_printf ("%s%s",
+                                      delta->old_file.path,
+                                      git_oid_tostr_s (&delta->old_file.id));
+       }
+       else
+       {
+               key = g_strdup_printf ("%s%s",
+                                      delta->new_file.path,
+                                      git_oid_tostr_s (&delta->new_file.id));
+       }
+
+       gdelta = g_hash_table_lookup (data->cached_deltas, key);
 
        if (!gdelta)
        {
                gdelta = _ggit_diff_delta_wrap (delta);
-               g_hash_table_insert (data->cached_deltas, (gpointer) delta, gdelta);
+               g_hash_table_insert (data->cached_deltas, key, gdelta);
+       }
+       else
+       {
+               g_free (key);
        }
 
        return gdelta;
@@ -95,21 +113,42 @@ wrap_diff_delta_cached (CallbackWrapperData  *data,
 
 static GgitDiffHunk *
 wrap_diff_hunk_cached (CallbackWrapperData *data,
+                       const git_diff_delta *delta,
                        const git_diff_hunk *hunk)
 {
        GgitDiffHunk *ghunk;
+       gchar *key;
 
-       if (!hunk)
+       if (!delta || !hunk)
        {
                return NULL;
        }
 
-       ghunk = g_hash_table_lookup (data->cached_hunks, hunk);
+       if (delta->old_file.path != NULL)
+       {
+               key = g_strdup_printf ("%s%s%s",
+                                      delta->old_file.path,
+                                      git_oid_tostr_s (&delta->old_file.id),
+                                      hunk->header);
+       }
+       else
+       {
+               key = g_strdup_printf ("%s%s%s",
+                                      delta->new_file.path,
+                                      git_oid_tostr_s (&delta->new_file.id),
+                                      hunk->header);
+       }
+
+       ghunk = g_hash_table_lookup (data->cached_hunks, key);
 
        if (!ghunk)
        {
                ghunk = _ggit_diff_hunk_wrap (hunk);
-               g_hash_table_insert (data->cached_hunks, (gpointer) hunk, ghunk);
+               g_hash_table_insert (data->cached_hunks, g_strdup (key), ghunk);
+       }
+       else
+       {
+               g_free (key);
        }
 
        return ghunk;
@@ -195,7 +234,7 @@ ggit_diff_hunk_callback_wrapper (const git_diff_delta *delta,
        gint ret;
 
        gdelta = wrap_diff_delta_cached (data, delta);
-       ghunk = wrap_diff_hunk_cached (data, hunk);
+       ghunk = wrap_diff_hunk_cached (data, delta, hunk);
 
        ret = data->hunk_cb (gdelta, ghunk, data->user_data);
 
@@ -228,7 +267,7 @@ ggit_diff_line_callback_wrapper (const git_diff_delta *delta,
        }
 
        gdelta = wrap_diff_delta_cached (data, delta);
-       ghunk = wrap_diff_hunk_cached (data, hunk);
+       ghunk = wrap_diff_hunk_cached (data, delta, hunk);
 
        gline = line == NULL ? NULL : _ggit_diff_line_wrap (line, encoding);
 
@@ -613,8 +652,8 @@ ggit_diff_foreach (GgitDiff              *diff,
        wrapper_data.user_data = user_data;
        wrapper_data.diff = diff;
 
-       wrapper_data.cached_deltas = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, 
(GDestroyNotify) ggit_diff_delta_unref);
-       wrapper_data.cached_hunks = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, 
(GDestroyNotify) ggit_diff_hunk_unref);
+       wrapper_data.cached_deltas = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) 
ggit_diff_delta_unref);
+       wrapper_data.cached_hunks = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) 
ggit_diff_hunk_unref);
 
        if (file_cb != NULL)
        {


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