barnowl/barnowl — pull request #90 by JasonGross (2012-02-11 01:14:41+00:00)
Title: Defer failed log messages

Previously, when we failed to open a logging file, we errored, and
dropped the log message. This commit makes it so we instead add the
log entry to a queue of messages to be logged eventually. We attempt to
log every entry in this queue, sequentially, whenever we get a new
message to log, and also when the user quits BarnOwl.

I decided to attempt to log all messages in the queue whenever we got a
new message, rather than only logging messages if the first one was
successful, because if we only check the first message, we run the risk
of blocking all logs forever on a single message that thinks it should
be logged to an invalid file. The implementation I chose has the
possible failure mode of logging messages out of order if we regain the
ability to write to files half way through trying to log deferred
messages.

This is done by adding every message that we want to log to the queue of
deferred log entries (via owl_log_eventually_write_entry and
owl_log_deferred_enqueue_message), and then attempting to log all the
messages in the queue (owl_log_write_deferred_entries).

I'm not entirely satisfied with the fact that I pass around GPtrArray**
in some places; I do this so that owl_log_write_deferred_entries can set
the entry queue to a new empty array before trying to log the messages
in the original queue (passed as a parameter).

I pass around the entry queue as a parameter, rather than always
referring to the global deferred_entry_queue, because I got intermittent
segfaults on quitting BarnOwl when I split up the final flushing of the
deferred entry queue and its freeing in owl_log_shutdown. I suspect
this was due to raciness in the callbacks passed to subsequent calls of
owl_select_post_task, but I'm not sure, and I didn't do extensive
debugging.