+ change = ovsdb_jsonrpc_monitor_row_find(mt, uuid);
+ if (!change) {
+ change = xmalloc(sizeof *change);
+ hmap_insert(&mt->changes, &change->hmap_node, uuid_hash(uuid));
+ change->uuid = *uuid;
+ change->old = clone_monitor_row_data(mt, old);
+ change->new = clone_monitor_row_data(mt, new);
+ } else {
+ if (new) {
+ update_monitor_row_data(mt, new, change->new);
+ } else {
+ free_monitor_row_data(mt, change->new);
+ change->new = NULL;
+
+ if (!change->old) {
+ /* This row was added then deleted. Forget about it. */
+ hmap_remove(&mt->changes, &change->hmap_node);
+ free(change);
+ }
+ }
+ }
+ return true;
+}
+
+/* Returns JSON for a <row-update> (as described in RFC 7047) for 'row' within
+ * 'mt', or NULL if no row update should be sent.
+ *
+ * The caller should specify 'initial' as true if the returned JSON is going to
+ * be used as part of the initial reply to a "monitor" request, false if it is
+ * going to be used as part of an "update" notification.
+ *
+ * 'changed' must be a scratch buffer for internal use that is at least
+ * bitmap_n_bytes(mt->n_columns) bytes long. */
+static struct json *
+ovsdb_jsonrpc_monitor_compose_row_update(
+ const struct ovsdb_jsonrpc_monitor_table *mt,
+ const struct ovsdb_jsonrpc_monitor_row *row,
+ bool initial, unsigned long int *changed)
+{
+ enum ovsdb_jsonrpc_monitor_selection type;
+ struct json *old_json, *new_json;
+ struct json *row_json;
+ size_t i;
+
+ type = (initial ? OJMS_INITIAL
+ : !row->old ? OJMS_INSERT
+ : !row->new ? OJMS_DELETE