]> git.street.me.uk Git - andy/viking.git/commitdiff
Use an internal thread concurrency model
authorGuilhem Bonnefille <guilhem.bonnefille@gmail.com>
Sat, 24 Oct 2009 19:57:19 +0000 (21:57 +0200)
committerGuilhem Bonnefille <guilhem.bonnefille@gmail.com>
Sat, 24 Oct 2009 19:57:19 +0000 (21:57 +0200)
Previous model was based on file: an existing *.tmp file signify a thread is downloading.
This model is not error prone: when viking failed to remove such a file (core dump?),
it won't be able to download this tile in the future.

Now, the concurrency between threads is handle internally: a list contains
all tmp files currently in use. By this way, thread exclude each other and
locks are clean at start.

Drawback: this model does not allow concurrency between multiple instance
of viking.

src/download.c
src/download.h
src/main.c

index e973ab8c148cf4e37d1eb4c4752b8a8c114152b8..bb3cb295f86f39541eaf8abde52381ab9440fc35 100644 (file)
@@ -93,6 +93,35 @@ gboolean a_check_kml_file(FILE* f)
   return check_file_first_line(f, kml_str);
 }
 
+static GList *file_list = NULL;
+static GMutex *file_list_mutex = NULL;
+
+void a_download_init (void)
+{
+       file_list_mutex = g_mutex_new();
+}
+
+static gboolean lock_file(const char *fn)
+{
+       gboolean locked = FALSE;
+       g_mutex_lock(file_list_mutex);
+       if (g_list_find(file_list, fn) == NULL)
+       {
+               // The filename is not yet locked
+               file_list = g_list_append(file_list, (gpointer)fn),
+               locked = TRUE;
+       }
+       g_mutex_unlock(file_list_mutex);
+       return locked;
+}
+
+static void unlock_file(const char *fn)
+{
+       g_mutex_lock(file_list_mutex);
+       file_list = g_list_remove(file_list, (gconstpointer)fn);
+       g_mutex_unlock(file_list_mutex);
+}
+
 static int download( const char *hostname, const char *uri, const char *fn, DownloadOptions *options, gboolean ftp)
 {
   FILE *f;
@@ -120,10 +149,15 @@ static int download( const char *hostname, const char *uri, const char *fn, Down
   }
 
   tmpfilename = g_strdup_printf("%s.tmp", fn);
-  f = g_fopen ( tmpfilename, "w+bx" );  /* truncate file and open it in exclusive mode */
+  if (!lock_file ( tmpfilename ) )
+  {
+    g_debug("%s: Couldn't take lock on temporary file \"%s\"\n", __FUNCTION__, tmpfilename);
+    g_free ( tmpfilename );
+    return -4;
+  }
+  f = g_fopen ( tmpfilename, "w+b" );  /* truncate file and open it */
   if ( ! f ) {
-    if (errno == EEXIST)
-      g_debug("%s: Couldn't take lock on temporary file \"%s\"\n", __FUNCTION__, tmpfilename);
+    g_warning("Couldn't open temporary file \"%s\": %s", tmpfilename, g_strerror(errno));
     g_free ( tmpfilename );
     return -4;
   }
@@ -145,6 +179,7 @@ static int download( const char *hostname, const char *uri, const char *fn, Down
   {
     g_warning(_("Download error: %s"), fn);
     g_remove ( tmpfilename );
+    unlock_file ( tmpfilename );
     g_free ( tmpfilename );
     fclose ( f );
     f = NULL;
@@ -156,6 +191,7 @@ static int download( const char *hostname, const char *uri, const char *fn, Down
     g_remove ( tmpfilename );
   else
     g_rename ( tmpfilename, fn ); /* move completely-downloaded file to permanent location */
+  unlock_file ( tmpfilename );
   g_free ( tmpfilename );
   fclose ( f );
   f = NULL;
index 109bc4c4bad0e77c1a97ce9d142c696495c0f14f..552187b9238edbc7356dbe71820f4f6621a802e0 100644 (file)
@@ -56,6 +56,8 @@ typedef struct {
 
 } DownloadOptions;
 
+void a_download_init(void);
+
 /* TODO: convert to Glib */
 int a_http_download_get_url ( const char *hostname, const char *uri, const char *fn, DownloadOptions *opt );
 int a_ftp_download_get_url ( const char *hostname, const char *uri, const char *fn, DownloadOptions *opt );
index 81cd6ea3e8d423890d3d29e646c5090a341648fd..5bbd022736ee2021dbe49892cbc13113c5cb9774 100644 (file)
@@ -165,6 +165,7 @@ int main( int argc, char *argv[] )
   if (!vik_debug)
     g_log_set_handler (NULL, G_LOG_LEVEL_DEBUG, mute_log, NULL);
 
+  a_download_init();
   curl_download_init();
 
   a_preferences_init ();