From ae2fcecc4ccc0a3b995d1558793fd0545495a53e Mon Sep 17 00:00:00 2001 From: Jann Horn Date: Mon, 18 Aug 2014 20:01:13 +0200 Subject: [PATCH] ~factor 40 speedup First write all files, then sync all filesystems, then move all files. The original behavior was very slow for two reasons: - After every file creation, we had to wait for the harddisk to complete the write. - We told the kernel and the harddisk in which order writes should happen. This reduces the time needed on my harddisk from 44-45s to 0.9-1.4s. --- update-mime-database.c | 57 +++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/update-mime-database.c b/update-mime-database.c index be4aba2..158dd09 100644 --- a/update-mime-database.c +++ b/update-mime-database.c @@ -85,6 +85,13 @@ struct _Type { char *media; char *subtype; + /* Contains the path under which the temporary file describing the + * type has been written. Only set to a meaningful value between + * file creation (write_out_type_tmpfile) and the file getting + * moved to its final name (move_type_file). + */ + char *filename; + /* Contains xmlNodes for elements that are being copied to the output. * That is, , and nodes, and anything * with an unknown namespace. @@ -1014,11 +1021,11 @@ out: } /* Write out an XML file for one type */ -static void write_out_type(gpointer key, gpointer value, gpointer data) +static void write_out_type_tmpfile(gpointer key, gpointer value, gpointer data) { Type *type = (Type *) value; const char *mime_dir = (char *) data; - char *media, *filename; + char *media; GError *local_error = NULL; char *lower; @@ -1032,18 +1039,49 @@ static void write_out_type(gpointer key, gpointer value, gpointer data) #endif lower = g_ascii_strdown(type->subtype, -1); - filename = g_strconcat(media, "/", lower, ".xml.new", NULL); + type->filename = g_strconcat(media, "/", lower, ".xml.new", NULL); g_free(lower); g_free(media); media = NULL; - if (!save_xml_file(type->output, filename, &local_error)) + if (!save_xml_file(type->output, type->filename, &local_error)) fatal_gerror(local_error); +} - if (!atomic_update(filename, &local_error)) - fatal_gerror(local_error); +/* Move the XML file to its correct name */ +static void move_type_file(gpointer key, gpointer value, gpointer data) +{ + Type *type = (Type *) value; + gchar *new_name = NULL; + int len; + GError *error = NULL; + + /* Actually, we already synced the file with sync() - here we + check whether the sync was successful. */ + if (sync_file(type->filename, &error) == -1) + fatal_gerror(error); + + len = strlen(type->filename); - g_free(filename); + if (strcmp(type->filename + len - 4, ".new") != 0) + g_error("expected temporary filename to end with .new"); + + new_name = g_strndup(type->filename, len - 4); + +#ifdef _WIN32 + /* we need to remove the old file first! */ + remove(new_name); +#endif + if (rename(type->filename, new_name) == -1) + { + g_printerr("Failed to rename %s as %s: %s\n", type->filename, new_name, + g_strerror(errno)); + exit (EXIT_FAILURE); + } + + g_free(new_name); + g_free(type->filename); + type->filename = NULL; } /* Comparison function to get the magic rules in priority order */ @@ -3697,7 +3735,10 @@ int main(int argc, char **argv) delete_old_types(mime_dir); - g_hash_table_foreach(types, write_out_type, (gpointer) mime_dir); + g_hash_table_foreach(types, write_out_type_tmpfile, (gpointer) mime_dir); + if (sync_enabled()) + sync(); + g_hash_table_foreach(types, move_type_file, NULL); { FILE *globs; -- 2.0.1