Blob Blame History Raw
From 2a4e2782a1faaf8e7bf5d4123e572007e591d24b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ale=C5=A1=20Mat=C4=9Bj?= <amatej@redhat.com>
Date: Tue, 23 Apr 2019 10:07:59 +0200
Subject: [PATCH] Prevent race condition when --update & we have duplicate pkgs
 (RhBug: 1696808)

---
 src/createrepo_c.c  |  2 ++
 src/dumper_thread.c | 12 ++++++++----
 src/dumper_thread.h |  1 +
 3 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/src/createrepo_c.c b/src/createrepo_c.c
index 444d88f..160789b 100644
--- a/src/createrepo_c.c
+++ b/src/createrepo_c.c
@@ -995,6 +995,7 @@ main(int argc, char **argv)
     user_data.id_oth            = 0;
     user_data.buffer            = g_queue_new();
     user_data.mutex_buffer      = g_mutex_new();
+    user_data.mutex_old_md      = g_mutex_new();
     user_data.deltas            = cmd_options->deltas;
     user_data.max_delta_rpm_size= cmd_options->max_delta_rpm_size;
     user_data.mutex_deltatargetpackages = g_mutex_new();
@@ -1049,6 +1050,7 @@ main(int argc, char **argv)
 
     g_queue_free(user_data.buffer);
     g_mutex_free(user_data.mutex_buffer);
+    g_mutex_free(user_data.mutex_old_md);
     g_cond_free(user_data.cond_pri);
     g_cond_free(user_data.cond_fil);
     g_cond_free(user_data.cond_oth);
diff --git a/src/dumper_thread.c b/src/dumper_thread.c
index 27c2493..589ab52 100644
--- a/src/dumper_thread.c
+++ b/src/dumper_thread.c
@@ -436,9 +436,15 @@ cr_dumper_thread(gpointer data, gpointer user_data)
     // Update stuff
     if (udata->old_metadata) {
         // We have old metadata
+        g_mutex_lock(udata->mutex_old_md);
         md = (cr_Package *) g_hash_table_lookup(
                                 cr_metadata_hashtable(udata->old_metadata),
                                 task->filename);
+        // Remove the pkg from the hash table of old metadata, so that no other
+        // thread can use it as CACHE, because later we modify it destructively
+        g_hash_table_steal(cr_metadata_hashtable(udata->old_metadata),
+                                                 task->filename);
+        g_mutex_unlock(udata->mutex_old_md);
 
         if (md) {
             g_debug("CACHE HIT %s", task->filename);
@@ -576,8 +582,7 @@ cr_dumper_thread(gpointer data, gpointer user_data)
     write_pkg(task->id, res, pkg, udata);
 
     // Clean up
-    if (pkg != md)
-        cr_package_free(pkg);
+    cr_package_free(pkg);
     g_free(res.primary);
     g_free(res.filelists);
     g_free(res.other);
@@ -623,8 +628,7 @@ cr_dumper_thread(gpointer data, gpointer user_data)
             // Dump XML and SQLite
             write_pkg(buf_task->id, buf_task->res, buf_task->pkg, udata);
             // Clean up
-            if (!buf_task->pkg_from_md)
-                cr_package_free(buf_task->pkg);
+            cr_package_free(buf_task->pkg);
             g_free(buf_task->res.primary);
             g_free(buf_task->res.filelists);
             g_free(buf_task->res.other);
diff --git a/src/dumper_thread.h b/src/dumper_thread.h
index 94a57d8..74d5951 100644
--- a/src/dumper_thread.h
+++ b/src/dumper_thread.h
@@ -71,6 +71,7 @@ struct UserData {
     // Update stuff
     gboolean skip_stat;             // Skip stat() while updating
     cr_Metadata *old_metadata;      // Loaded metadata
+    GMutex *mutex_old_md;           // Mutex for accessing old metadata
 
     // Thread serialization
     GMutex *mutex_pri;              // Mutex for primary metadata