monitor: Throttle event VSERPORT_CHANGE separately by "id"
VSERPORT_CHANGE is emitted when the guest opens or closes a
virtio-serial port. The event's member "id" identifies the port.
When several events arrive quickly, throttling drops all but the last
of them. Because of that, a QMP client must assume that *any* port
may have changed state when it receives a VSERPORT_CHANGE event and
throttling may have happened.
Make the event more useful by throttling it for each port separately.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-Id: <1444921716-9511-7-git-send-email-armbru@redhat.com>
diff --git a/monitor.c b/monitor.c
index 525d8e4..6cd747f 100644
--- a/monitor.c
+++ b/monitor.c
@@ -181,7 +181,8 @@
* instance.
*/
typedef struct MonitorQAPIEventState {
- QAPIEvent event; /* Event being tracked */
+ QAPIEvent event; /* Throttling state for this event type and... */
+ QDict *data; /* ... data, see qapi_event_throttle_equal() */
QEMUTimer *timer; /* Timer for handling delayed events */
QDict *qdict; /* Delayed event (if any) */
} MonitorQAPIEventState;
@@ -490,7 +491,8 @@
/* Unthrottled event */
monitor_qapi_event_emit(event, qdict);
} else {
- MonitorQAPIEventState key = { .event = event };
+ QDict *data = qobject_to_qdict(qdict_get(qdict, "data"));
+ MonitorQAPIEventState key = { .event = event, .data = data };
evstate = g_hash_table_lookup(monitor_qapi_event_state, &key);
assert(!evstate || timer_pending(evstate->timer));
@@ -517,6 +519,8 @@
evstate = g_new(MonitorQAPIEventState, 1);
evstate->event = event;
+ evstate->data = data;
+ QINCREF(evstate->data);
evstate->qdict = NULL;
evstate->timer = timer_new_ns(QEMU_CLOCK_REALTIME,
monitor_qapi_event_handler,
@@ -551,6 +555,7 @@
timer_mod_ns(evstate->timer, now + evconf->rate);
} else {
g_hash_table_remove(monitor_qapi_event_state, evstate);
+ QDECREF(evstate->data);
timer_free(evstate->timer);
g_free(evstate);
}
@@ -561,8 +566,13 @@
static unsigned int qapi_event_throttle_hash(const void *key)
{
const MonitorQAPIEventState *evstate = key;
+ unsigned int hash = evstate->event * 255;
- return evstate->event * 255;
+ if (evstate->event == QAPI_EVENT_VSERPORT_CHANGE) {
+ hash += g_str_hash(qdict_get_str(evstate->data, "id"));
+ }
+
+ return hash;
}
static gboolean qapi_event_throttle_equal(const void *a, const void *b)
@@ -570,7 +580,16 @@
const MonitorQAPIEventState *eva = a;
const MonitorQAPIEventState *evb = b;
- return eva->event == evb->event;
+ if (eva->event != evb->event) {
+ return FALSE;
+ }
+
+ if (eva->event == QAPI_EVENT_VSERPORT_CHANGE) {
+ return !strcmp(qdict_get_str(eva->data, "id"),
+ qdict_get_str(evb->data, "id"));
+ }
+
+ return TRUE;
}
static void monitor_qapi_event_init(void)