};
static void
-stats_event_write(struct event *event, struct event *global_event,
+stats_event_write(struct stats_client *client,
+ struct event *event, struct event *global_event,
const struct failure_context *ctx, string_t *str, bool begin)
{
struct event *merged_event;
struct event *parent_event;
- bool update = FALSE;
+ bool update = FALSE, flush_output = FALSE;
merged_event = begin ? event_ref(event) : event_minimize(event);
parent_event = merged_event->parent;
if (parent_event != NULL) {
if (parent_event->sent_to_stats_id !=
- parent_event->change_id)
- stats_event_write(parent_event, NULL, ctx, str, TRUE);
+ parent_event->change_id) {
+ stats_event_write(client, parent_event, NULL,
+ ctx, str, TRUE);
+ }
i_assert(parent_event->sent_to_stats_id != 0);
}
if (begin) {
const char *cmd = !update ? "BEGIN" : "UPDATE";
str_printfa(str, "%s\t%"PRIu64"\t", cmd, event->id);
event->sent_to_stats_id = event->change_id;
+ /* Flush the BEGINs early on, because the stats event writing
+ may trigger more events recursively (e.g. data_stack_grow),
+ which may use the BEGIN events as parents. */
+ flush_output = !update;
} else {
str_printfa(str, "EVENT\t%"PRIu64"\t",
global_event == NULL ? 0 : global_event->id);
event_export(merged_event, str);
str_append_c(str, '\n');
event_unref(&merged_event);
+ if (flush_output) {
+ o_stream_nsend(client->conn.output, str_data(str), str_len(str));
+ str_truncate(str, 0);
+ }
}
static void
stats_client_send_event(struct stats_client *client, struct event *event,
const struct failure_context *ctx)
{
+ static int recursion = 0;
+
if (!client->handshaked)
return;
/* Need to send the event for stats and/or export */
string_t *str = t_str_new(256);
+ if (++recursion == 0)
+ o_stream_cork(client->conn.output);
struct event *global_event = event_get_global();
if (global_event != NULL)
- stats_event_write(global_event, NULL, ctx, str, TRUE);
+ stats_event_write(client, global_event, NULL, ctx, str, TRUE);
- stats_event_write(event, global_event, ctx, str, FALSE);
+ stats_event_write(client, event, global_event, ctx, str, FALSE);
o_stream_nsend(client->conn.output, str_data(str), str_len(str));
+
+ i_assert(recursion > 0);
+ if (--recursion == 0)
+ o_stream_uncork(client->conn.output);
}
static void