From a1c5aa388f086a2450aae6180b1500c525f880bd Mon Sep 17 00:00:00 2001 From: Bradford Hovinen Date: Fri, 3 Aug 2001 14:38:09 +0000 Subject: [PATCH] Return NULL if fgets returns NULL (dump_log): If both first_old and 2001-08-03 Bradford Hovinen * config-log.c (load_log_entry): Return NULL if fgets returns NULL (dump_log): If both first_old and log_data are NULL, go ahead and dump the file, since nothing has been loaded yet (config_log_garbage_collect): Don't bother dumping the log file or reloading 2001-08-02 Bradford Hovinen * config-log.c (config_log_garbage_collect): Implement (dump_log): Don't dump the old file if first_old is NULL * main.c (main): Support --garbage_collect * location.c (location_garbage_collect): (garbage_collect_cb): Implement --- archiver/ChangeLog | 18 ++++++++ archiver/config-log.c | 105 ++++++++++++++++++++++++++++++++++++------ archiver/config-log.h | 46 ++++++++++-------- archiver/location.c | 39 +++++++++++++++- archiver/location.h | 2 + archiver/main.c | 11 +++++ 6 files changed, 185 insertions(+), 36 deletions(-) diff --git a/archiver/ChangeLog b/archiver/ChangeLog index dbc945488..821744f5b 100644 --- a/archiver/ChangeLog +++ b/archiver/ChangeLog @@ -1,3 +1,21 @@ +2001-08-03 Bradford Hovinen + + * config-log.c (load_log_entry): Return NULL if fgets returns NULL + (dump_log): If both first_old and log_data are NULL, go ahead and + dump the file, since nothing has been loaded yet + (config_log_garbage_collect): Don't bother dumping the log file or + reloading + +2001-08-02 Bradford Hovinen + + * config-log.c (config_log_garbage_collect): Implement + (dump_log): Don't dump the old file if first_old is NULL + + * main.c (main): Support --garbage_collect + + * location.c (location_garbage_collect): + (garbage_collect_cb): Implement + 2001-07-31 Bradford Hovinen * config-log.c: Remove socket-based synchronization system diff --git a/archiver/config-log.c b/archiver/config-log.c index eb0275d1e..8bdded61c 100644 --- a/archiver/config-log.c +++ b/archiver/config-log.c @@ -518,7 +518,7 @@ config_log_reset_filenames (ConfigLog *config_log) } /** - * config_log_reload + * config_log_reload: * @config_log: * * Reloads the entire config log, throwing out any newly created entries @@ -535,6 +535,84 @@ config_log_reload (ConfigLog *config_log) do_load (config_log); } +/** + * config_log_garbage_collect: + * @config_log: + * @backend_id: Backend on which to iterate + * @callback: Callback to issue on any log entry to be culled + * @data: Arbitrary data to pass to callback + * + * Iterates through the configuration log and culls excess entries for the given + * backend. + * + * The algorithm we use is the following: We scan entries in temporal order. For + * each consecutive pair of entries, let t1 be the time at which the former was + * made and t2 be the time of the latter. If K_CONST * (t2 - t1) < t2, then we + * delete the former entry and issue the callback. We select K_CONST + * appropriately, i.e. a user will likely not want to keep entries separated by + * under five minutes for very long, while she may want to keep entries + * separated by two weeks for much longer. + */ + +#define K_CONST 15 + +void +config_log_garbage_collect (ConfigLog *config_log, + gchar *backend_id, + GarbageCollectCB callback, + gpointer data) +{ + GList *node, *list = NULL; + ConfigLogEntry *e1, *e2; + time_t t1, t2, now; + + g_return_if_fail (config_log != NULL); + g_return_if_fail (IS_CONFIG_LOG (config_log)); + + if (config_log->p->log_data == NULL) + config_log->p->log_data = + load_log_entry (config_log, NULL); + + node = config_log->p->log_data; + + /* We build a list of config log nodes to facilitate removing the nodes + * from the main cache at a later point + */ + + while (1) { + node = find_config_log_entry_backend + (config_log, node, backend_id); + + if (node == NULL) + break; + + list = g_list_prepend (list, node); + node = node->next; + } + + if (list == NULL) return; + + now = time (NULL); + + for (node = list; node->next != NULL; node = node->next) { + e1 = ((GList *) node->data)->data; + e2 = ((GList *) node->next->data)->data; + + t1 = mktime (e1->date); + t2 = mktime (e2->date); + + if (K_CONST * (t2 - t1) < now - t2) { + config_log->p->log_data = + g_list_remove_link (config_log->p->log_data, node->data); + callback (config_log, backend_id, e1->id, data); + } + } + + g_list_free (list); + + config_log->p->first_old = NULL; +} + /* Find the config log entry with the id given, starting at the given * node. Return a pointer to the node. */ @@ -663,7 +741,8 @@ load_log_entry (ConfigLog *config_log, if (feof (config_log->p->file_stream)) return NULL; - fgets (buffer, 1024, config_log->p->file_stream); + if (fgets (buffer, 1024, config_log->p->file_stream) == NULL) + return NULL; entry = g_new0 (ConfigLogEntry, 1); entry->date = g_new0 (struct tm, 1); @@ -780,6 +859,7 @@ do_load (ConfigLog *config_log) g_return_val_if_fail (IS_CONFIG_LOG (config_log), FALSE); config_log->p->file_stream = fopen (config_log->p->filename, "r"); + config_log->p->first_old = NULL; return TRUE; } @@ -791,8 +871,6 @@ do_load (ConfigLog *config_log) static void do_unload (ConfigLog *config_log, gboolean write_log) { - GList *tmp; - g_return_if_fail (config_log != NULL); g_return_if_fail (IS_CONFIG_LOG (config_log)); @@ -808,13 +886,9 @@ do_unload (ConfigLog *config_log, gboolean write_log) config_log->p->filename = NULL; } - while (config_log->p->log_data != NULL) { - tmp = config_log->p->log_data->next; - config_log_entry_destroy - ((ConfigLogEntry *) config_log->p->log_data->data); - g_list_free_1 (config_log->p->log_data); - config_log->p->log_data = tmp; - } + g_list_foreach (config_log->p->log_data, (GFunc) config_log_entry_destroy, NULL); + g_list_free (config_log->p->log_data); + config_log->p->log_data = NULL; } /* Returns the next id number in the sequence */ @@ -905,13 +979,16 @@ dump_log (ConfigLog *config_log) first = first->next) write_log (output, first->data); - config_log->p->first_old = config_log->p->log_data; - - if (config_log->p->file_stream) { + if (config_log->p->file_stream != NULL && + ((config_log->p->first_old == NULL && config_log->p->log_data == NULL) || + (config_log->p->first_old != NULL && config_log->p->log_data != NULL))) + { rewind (config_log->p->file_stream); dump_file (config_log->p->file_stream, output); } + config_log->p->first_old = config_log->p->log_data; + fclose (output); if (config_log->p->filename) diff --git a/archiver/config-log.h b/archiver/config-log.h index 5ddf789e0..634a85bae 100644 --- a/archiver/config-log.h +++ b/archiver/config-log.h @@ -40,6 +40,7 @@ typedef struct _Location Location; typedef gint (*ConfigLogIteratorCB) (ConfigLog *, gint, gchar *, struct tm *, gpointer); +typedef void (*GarbageCollectCB) (ConfigLog *, gchar *, gint, gpointer); struct _ConfigLog { @@ -55,30 +56,35 @@ struct _ConfigLogClass guint config_log_get_type (void); -GtkObject *config_log_open (Location *location); -void config_log_delete (ConfigLog *config_log); +GtkObject *config_log_open (Location *location); +void config_log_delete (ConfigLog *config_log); -gint config_log_get_rollback_id_for_date (ConfigLog *config_log, - struct tm *date, - gchar *backend_id); -gint config_log_get_rollback_id_by_steps (ConfigLog *config_log, - guint steps, - gchar *backend_id); +gint config_log_get_rollback_id_for_date (ConfigLog *config_log, + struct tm *date, + gchar *backend_id); +gint config_log_get_rollback_id_by_steps (ConfigLog *config_log, + guint steps, + gchar *backend_id); -gchar *config_log_get_backend_id_for_id (ConfigLog *config_log, - gint id); -struct tm *config_log_get_date_for_id (ConfigLog *config_log, - gint id); +gchar *config_log_get_backend_id_for_id (ConfigLog *config_log, + gint id); +struct tm *config_log_get_date_for_id (ConfigLog *config_log, + gint id); -gint config_log_write_entry (ConfigLog *config_log, - gchar *backend_id, - gboolean is_default_data); +gint config_log_write_entry (ConfigLog *config_log, + gchar *backend_id, + gboolean is_default_data); -void config_log_iterate (ConfigLog *config_log, - ConfigLogIteratorCB callback, - gpointer data); +void config_log_iterate (ConfigLog *config_log, + ConfigLogIteratorCB callback, + gpointer data); -void config_log_reset_filenames (ConfigLog *config_log); -void config_log_reload (ConfigLog *config_log); +void config_log_reset_filenames (ConfigLog *config_log); +void config_log_reload (ConfigLog *config_log); + +void config_log_garbage_collect (ConfigLog *config_log, + gchar *backend_id, + GarbageCollectCB callback, + gpointer data); #endif /* __CONFIG_LOG */ diff --git a/archiver/location.c b/archiver/location.c index 3e6b25a1f..4f38cc62b 100644 --- a/archiver/location.c +++ b/archiver/location.c @@ -1280,6 +1280,42 @@ location_get_config_log (Location *location) return location->p->config_log; } +/* location_garbage_collect: + * @location: + * + * Iterates through backends and eliminates excess archived data from the + * configuration log and the XML archive + */ + +static void +garbage_collect_cb (ConfigLog *config_log, gchar *backend_id, gint id, Location *location) +{ + gchar *filename; + + filename = g_strdup_printf ("%s/%08x.xml", location->p->fullpath, id); + DEBUG_MSG ("Removing %s", filename); + unlink (filename); + g_free (filename); +} + +void +location_garbage_collect (Location *location) +{ + GList *node; + BackendNote *note; + + g_return_if_fail (location != NULL); + g_return_if_fail (IS_LOCATION (location)); + + for (node = location->p->contains_list; node != NULL; node = node->next) { + note = node->data; + config_log_garbage_collect (location->p->config_log, + note->backend_id, + (GarbageCollectCB) garbage_collect_cb, + location); + } +} + static gint get_backends_cb (BackendList *backend_list, gchar *backend_id, Location *location) @@ -1292,8 +1328,7 @@ get_backends_cb (BackendList *backend_list, gchar *backend_id, /* Construct the directory structure for a given location * - * FIXME: Better error reporting - */ + * FIXME: Better error reporting */ static gboolean do_create (Location *location) diff --git a/archiver/location.h b/archiver/location.h index b1940d741..382cc2f05 100644 --- a/archiver/location.h +++ b/archiver/location.h @@ -149,4 +149,6 @@ gboolean location_does_backend_change (Location *location, ConfigLog *location_get_config_log (Location *location); +void location_garbage_collect (Location *location); + #endif /* __LOCATION */ diff --git a/archiver/main.c b/archiver/main.c index a7bdf8ee0..8019e8910 100644 --- a/archiver/main.c +++ b/archiver/main.c @@ -44,6 +44,7 @@ static gboolean rollback; static gboolean change_location; static gboolean rename_location; static gboolean push_config; +static gboolean garbage_collect; static gboolean add_location; static gboolean remove_location; @@ -91,6 +92,8 @@ static struct poptOption archiver_operations[] = { N_("Add a given backend to the given location")}, {"remove-backend", '\0', POPT_ARG_NONE, &remove_backend, 0, N_("Remove the given backend from the given location")}, + {"garbage-collect", '\0', POPT_ARG_NONE, &garbage_collect, 0, + N_("Perform garbage collection on the given location")}, {NULL, '\0', 0, NULL, 0} }; @@ -297,6 +300,12 @@ do_remove_backend (Location *location) location_remove_backend (location, backend_id); } +static void +do_garbage_collect (Location *location) +{ + location_garbage_collect (location); +} + int main (int argc, char **argv) { @@ -365,6 +374,8 @@ main (int argc, char **argv) do_add_backend (location); else if (remove_backend) do_remove_backend (location); + else if (garbage_collect) + do_garbage_collect (location); archive_close (archive);