[gvfs/wip/oholy/google-cache-conservative: 38/39] google: Use cache for enumeration also



commit 649254c9fbf329af1e6f3b8a65c19d6e85c2ba62
Author: Ondrej Holy <oholy redhat com>
Date:   Thu Aug 16 15:00:52 2018 +0200

    google: Use cache for enumeration also
    
    The reworked cache hasn't been used for enumeration results and also
    for missing files checks, which always caused rebuilding cache. Let's
    save timestamps also for enumerations and use it to prevent redundant
    cache rebuilds.

 daemon/gvfsbackendgoogle.c | 62 ++++++++++++++++++++++++++++++++++------------
 1 file changed, 46 insertions(+), 16 deletions(-)
---
diff --git a/daemon/gvfsbackendgoogle.c b/daemon/gvfsbackendgoogle.c
index e3a579c4..142acd5e 100644
--- a/daemon/gvfsbackendgoogle.c
+++ b/daemon/gvfsbackendgoogle.c
@@ -57,6 +57,7 @@ struct _GVfsBackendGoogle
   GDataEntry *root;
   GHashTable *entries; /* gchar *entry_id -> GDataEntry */
   GHashTable *dir_entries; /* DirEntriesKey -> GDataEntry */
+  GHashTable *dir_timestamps; /* gchar *entry_id -> gint64 *timestamp */
   GHashTable *monitors;
   GList *dir_collisions;
   GRecMutex mutex; /* guards cache */
@@ -463,6 +464,8 @@ remove_entry_full (GVfsBackendGoogle *self,
     {
       gchar *parent_id = ll->data;
 
+      g_hash_table_remove (self->dir_timestamps, parent_id);
+
       k = dir_entries_key_new (id, parent_id);
       g_debug ("  remove_entry: Removed (%s, %s) -> %p\n", id, parent_id, entry);
       g_hash_table_remove (self->dir_entries, k);
@@ -519,6 +522,8 @@ remove_dir (GVfsBackendGoogle *self,
   /* g_strdup() is necessary to prevent segfault because gdata_entry_get_id() calls g_free() */
   parent_id = g_strdup (gdata_entry_get_id (parent));
 
+  g_hash_table_remove (self->dir_timestamps, parent_id);
+
   g_hash_table_iter_init (&iter, self->entries);
   while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &entry))
     {
@@ -562,6 +567,18 @@ is_entry_valid (GDataEntry *entry)
   return (g_get_real_time () - *timestamp < REBUILD_ENTRIES_TIMEOUT * G_USEC_PER_SEC);
 }
 
+static gboolean
+is_dir_listing_valid (GVfsBackendGoogle *self, GDataEntry *parent)
+{
+  gint64 *timestamp;
+
+  timestamp = g_hash_table_lookup (self->dir_timestamps, gdata_entry_get_id (parent));
+  if (timestamp != NULL)
+    return (g_get_real_time () - *timestamp < REBUILD_ENTRIES_TIMEOUT * G_USEC_PER_SEC);
+
+  return FALSE;
+}
+
 static void
 rebuild_dir (GVfsBackendGoogle  *self,
              GDataEntry         *parent,
@@ -572,9 +589,10 @@ rebuild_dir (GVfsBackendGoogle  *self,
   GDataDocumentsQuery *query = NULL;
   gboolean succeeded_once = FALSE;
   gchar *search;
-  const gchar *parent_id;
+  gchar *parent_id;
 
-  parent_id = gdata_entry_get_id (parent);
+  /* g_strdup() is necessary to prevent segfault because gdata_entry_get_id() calls g_free() */
+  parent_id = g_strdup (gdata_entry_get_id (parent));
 
   search = g_strdup_printf ("'%s' in parents", parent_id);
   query = gdata_documents_query_new_with_limits (search, 1, MAX_RESULTS);
@@ -599,8 +617,14 @@ rebuild_dir (GVfsBackendGoogle  *self,
 
       if (!succeeded_once)
         {
+          gint64 *timestamp;
+
           remove_dir (self, parent);
 
+          timestamp = g_new (gint64, 1);
+          *timestamp = g_get_real_time ();
+          g_hash_table_insert (self->dir_timestamps, g_strdup (parent_id), timestamp);
+
           succeeded_once = TRUE;
         }
 
@@ -621,6 +645,7 @@ rebuild_dir (GVfsBackendGoogle  *self,
  out:
   g_clear_object (&feed);
   g_clear_object (&query);
+  g_free (parent_id);
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
@@ -640,8 +665,8 @@ resolve_child (GVfsBackendGoogle  *self,
   parent_id = gdata_entry_get_id (parent);
   k = dir_entries_key_new (basename, parent_id);
   entry = g_hash_table_lookup (self->dir_entries, k);
-  // TODO: Rebuild only if dir listing is not valid
-  if (entry == NULL || !is_entry_valid (entry))
+  if ((entry == NULL && !is_dir_listing_valid (self, parent)) ||
+      (entry != NULL && !is_entry_valid (entry)))
     {
       rebuild_dir (self, parent, cancellable, &local_error);
       if (local_error != NULL)
@@ -651,11 +676,12 @@ resolve_child (GVfsBackendGoogle  *self,
         }
 
       entry = g_hash_table_lookup (self->dir_entries, k);
-      if (entry == NULL)
-        {
-          g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, _("No such file or directory"));
-          goto out;
-        }
+    }
+
+  if (entry == NULL)
+    {
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, _("No such file or directory"));
+      goto out;
     }
 
  out:
@@ -1355,7 +1381,7 @@ g_vfs_backend_google_enumerate (GVfsBackend           *_self,
   GError *error;
   GHashTableIter iter;
   char *parent_path;
-  char *id;
+  char *id = NULL;
 
   g_rec_mutex_lock (&self->mutex);
   g_debug ("+ enumerate: %s\n", filename);
@@ -1375,13 +1401,15 @@ g_vfs_backend_google_enumerate (GVfsBackend           *_self,
       goto out;
     }
 
-  // TODO: Rebuild only if dir listing is not valid
-  rebuild_dir (self, entry, cancellable, &error);
-  if (error != NULL)
+  if (!is_dir_listing_valid (self, entry))
     {
-      g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
-      g_error_free (error);
-      goto out;
+      rebuild_dir (self, entry, cancellable, &error);
+      if (error != NULL)
+        {
+          g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
+          g_error_free (error);
+          goto out;
+        }
     }
 
   g_vfs_job_succeeded (G_VFS_JOB (job));
@@ -2757,6 +2785,7 @@ g_vfs_backend_google_dispose (GObject *_self)
   g_clear_object (&self->client);
   g_clear_pointer (&self->entries, g_hash_table_unref);
   g_clear_pointer (&self->dir_entries, g_hash_table_unref);
+  g_clear_pointer (&self->dir_timestamps, g_hash_table_unref);
 
   G_OBJECT_CLASS (g_vfs_backend_google_parent_class)->dispose (_self);
 }
@@ -2815,6 +2844,7 @@ g_vfs_backend_google_init (GVfsBackendGoogle *self)
                                              entries_in_folder_equal,
                                              dir_entries_key_free,
                                              g_object_unref);
+  self->dir_timestamps = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
   self->monitors = g_hash_table_new (NULL, NULL);
   g_rec_mutex_init (&self->mutex);
 }


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