On 07/30/2012 09:43 AM, Jakub Filak wrote:
> * concurrent run of post-create event may mark all processed problems as
>   duplicates of each other and delete all of them
> * abrtd accepts notifications and pushes a problem directory to a queue
> * after processing of one problem abrtd pops a directory from the queue
>   and continues of processing with next directory
> 
> Signed-off-by: Jakub Filak <[email protected]>
> ---
>  src/daemon/abrtd.c |   66 
> ++++++++++++++++++++++++++++++++++++++++++----------
>  1 file changed, 54 insertions(+), 12 deletions(-)
> 
> diff --git a/src/daemon/abrtd.c b/src/daemon/abrtd.c
> index 1112591..c664a66 100644
> --- a/src/daemon/abrtd.c
> +++ b/src/daemon/abrtd.c
> @@ -74,6 +74,24 @@ static int child_count = 0;
>   */
>  static GList *s_pid_list;
>  
> +/*
> + * The post-create event cannot be run concurrently for more problem
> + * directories. The problem is in searching for duplicates process in case 
> when
> + * two concurrently processed directories are duplicates of each other. Both 
> of
> + * the directories are marked as duplicates of each other and are deleted.
> + *
> + * This queue is used for serialization of processing of created problem
> + * directories.
> + *
> + * The GIO notify handler pushes new directories to this queue and if the 
> queue was
> + * empty before push then starts processing of the pushed directory.
> + *
> + * Directory processing code pops the processed directory from the queue at 
> the
> + * end of processing. If the queue is not empty starts processing of the next
> + * directory which is on the top of the queue.
> + */
> +static GList *s_dir_queue;
> +
>  enum {
>      EVTYPE_POST_CREATE,
>      EVTYPE_NOTIFY,
> @@ -291,6 +309,25 @@ static gboolean handle_signal_cb(GIOChannel *gio, 
> GIOCondition condition, gpoint
>      return TRUE; /* "please don't remove this event" */
>  }
>  
> +static gboolean handle_event_output_cb(GIOChannel *gio, GIOCondition 
> condition, gpointer ptr);
> +
> +/* Runs post-create event asynchronously. Uses GIOChanel for communication 
> with event process. */
> +static void run_post_create_on_dir_async(const char *name)
> +{
> +    struct event_processing_state *state = new_event_processing_state();
> +    state->event_type = EVTYPE_POST_CREATE;
> +    state->dirname = concat_path_file(g_settings_dump_location, name);
> +
> +    state->child_pid = spawn_event_handler_child(state->dirname, 
> "post-create", &state->child_stdout_fd);
> +    s_pid_list = g_list_prepend(s_pid_list, state);
> +    ndelay_on(state->child_stdout_fd);
> +
> +    GIOChannel *channel_event_output = 
> my_io_channel_unix_new(state->child_stdout_fd);
> +    /*uint channel_id_event_output =*/ g_io_add_watch(channel_event_output,
> +            G_IO_IN | G_IO_PRI | G_IO_HUP,
> +            handle_event_output_cb,
> +            state);
> +}
>  
>  /* Event-processing child output handler (such as "post-create" event) */
>  static gboolean handle_event_output_cb(GIOChannel *gio, GIOCondition 
> condition, gpointer ptr)
> @@ -435,11 +472,21 @@ static gboolean handle_event_output_cb(GIOChannel *gio, 
> GIOCondition condition,
>  
>      /* We stop using this channel */
>      g_io_channel_unref(gio);
> +
> +    /* pop the currently processed directory from the incoming queue */
> +    char *name = s_dir_queue->data;
> +    s_dir_queue = g_list_remove(s_dir_queue, name);
> +    free(name);
> +
> +    /* if the queue is not empty process directory from */
> +    /* the top of the incoming queue */
> +    if (s_dir_queue)
> +        run_post_create_on_dir_async(s_dir_queue->data);
> +
>      return FALSE; /* "glib, please remove this events source!" */
>      /* Removing will also drop the last ref to this gio, closing/freeing it 
> */
>  }
>  
> -
>  /* Inotify handler */
>  
>  static gboolean handle_inotify_cb(GIOChannel *gio, GIOCondition condition, 
> gpointer ptr_unused)
> @@ -550,19 +597,14 @@ static gboolean handle_inotify_cb(GIOChannel *gio, 
> GIOCondition condition, gpoin
>              }
>          }
>  
> -        struct event_processing_state *state = new_event_processing_state();
> -        state->event_type = EVTYPE_POST_CREATE;
> -        state->dirname = concat_path_file(g_settings_dump_location, name);
> +        const bool empty_queue = s_dir_queue == NULL;
> +        /* push the new directory to the end of the incoming queue */
> +        s_dir_queue = g_list_append(s_dir_queue, xstrdup(name));
>  
> -        state->child_pid = spawn_event_handler_child(state->dirname, 
> "post-create", &state->child_stdout_fd);
> -        s_pid_list = g_list_prepend(s_pid_list, state);
> -        ndelay_on(state->child_stdout_fd);
> +        /* if the queue was empty process the current directory */
> +        if (empty_queue)
> +            run_post_create_on_dir_async(name);
>  
> -        GIOChannel *channel_event_output = 
> my_io_channel_unix_new(state->child_stdout_fd);
> -        /*uint channel_id_event_output =*/ 
> g_io_add_watch(channel_event_output,
> -                                              G_IO_IN | G_IO_PRI | G_IO_HUP,
> -                                              handle_event_output_cb,
> -                                              state);
>      } /* while */
>  
>      free(buf);

Looks good to me.

Reply via email to