mirror of
https://github.com/openvswitch/ovs
synced 2025-08-30 22:05:19 +00:00
lib: add diff and apply diff APIs for ovsdb_datum
When an OVSDB column change its value, it is more efficient to only send what has changed, rather than sending the entire new copy. This is analogous to software programmer send patches rather than the entire source file. For columns store a single element, the "diff" datum is the same as the "new" datum. For columns that store set or map, it is only necessary to send the information about the elements changed (including addition or removal). The "diff" for those types are all elements that are changed. Those APIs are mainly used for implementing a new OVSDB server "update2" JSON-RPC notification, which encodes modifications of a column with the contents of those "diff"s. Later patch implements the "update2" notification. Signed-off-by: Andy Zhou <azhou@nicira.com> Acked-by: Ben Pfaff <blp@ovn.org>
This commit is contained in:
@@ -1904,6 +1904,89 @@ ovsdb_symbol_table_insert(struct ovsdb_symbol_table *symtab,
|
||||
}
|
||||
return symbol;
|
||||
}
|
||||
|
||||
/* APIs for Generating and apply diffs. */
|
||||
|
||||
/* Generate a difference ovsdb_dataum between 'old' and 'new'.
|
||||
* 'new' can be regenerated by applying the difference to the 'old'.
|
||||
*
|
||||
* The diff operation is reversible. Given 'old',
|
||||
* 'new' can be recreated by applying diff to 'old'.
|
||||
*
|
||||
* Thus
|
||||
* Let d = 'old' diff 'new'
|
||||
* then 'new' = 'old' diff d
|
||||
*
|
||||
* The 'diff' datum is always safe; the orders of keys are maintained
|
||||
* since they are added in order. */
|
||||
void
|
||||
ovsdb_datum_diff(struct ovsdb_datum *diff,
|
||||
const struct ovsdb_datum *old,
|
||||
const struct ovsdb_datum *new,
|
||||
const struct ovsdb_type *type)
|
||||
{
|
||||
size_t oi, ni;
|
||||
|
||||
ovsdb_datum_init_empty(diff);
|
||||
if (!ovsdb_type_is_composite(type)) {
|
||||
ovsdb_datum_clone(diff, new, type);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Generate the diff in O(n) time. */
|
||||
for (oi = ni = 0; oi < old->n && ni < new->n; ) {
|
||||
int c = ovsdb_atom_compare_3way(&old->keys[oi], &new->keys[ni],
|
||||
type->key.type);
|
||||
if (c < 0) {
|
||||
ovsdb_datum_add_unsafe(diff, &old->keys[oi], &old->values[oi],
|
||||
type);
|
||||
oi++;
|
||||
} else if (c > 0) {
|
||||
ovsdb_datum_add_unsafe(diff, &new->keys[ni], &new->values[ni],
|
||||
type);
|
||||
ni++;
|
||||
} else {
|
||||
if (type->value.type != OVSDB_TYPE_VOID &&
|
||||
ovsdb_atom_compare_3way(&old->values[oi], &new->values[ni],
|
||||
type->value.type)) {
|
||||
ovsdb_datum_add_unsafe(diff, &new->keys[ni], &new->values[ni],
|
||||
type);
|
||||
}
|
||||
oi++; ni++;
|
||||
}
|
||||
}
|
||||
|
||||
for (; oi < old->n; oi++) {
|
||||
ovsdb_datum_add_unsafe(diff, &old->keys[oi], &old->values[oi], type);
|
||||
}
|
||||
|
||||
for (; ni < new->n; ni++) {
|
||||
ovsdb_datum_add_unsafe(diff, &new->keys[ni], &new->values[ni], type);
|
||||
}
|
||||
}
|
||||
|
||||
/* Apply 'diff' to 'old' to regenerate 'new'.
|
||||
*
|
||||
* Return NULL if the 'new' is successfully generated, otherwise, return
|
||||
* ovsdb_error and the stat of 'new' is indeterministic. */
|
||||
struct ovsdb_error *
|
||||
ovsdb_datum_apply_diff(struct ovsdb_datum *new,
|
||||
const struct ovsdb_datum *old,
|
||||
const struct ovsdb_datum *diff,
|
||||
const struct ovsdb_type *type)
|
||||
{
|
||||
ovsdb_datum_init_empty(new);
|
||||
ovsdb_datum_diff(new, old, diff, type);
|
||||
|
||||
/* Make sure member size of 'new' conforms to type. */
|
||||
if (new->n < type->n_min || new->n > type->n_max) {
|
||||
ovsdb_datum_destroy(new, type);
|
||||
return ovsdb_error(NULL, "Datum crated by diff has size error");
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Extracts a token from the beginning of 's' and returns a pointer just after
|
||||
* the token. Stores the token itself into '*outp', which the caller is
|
||||
|
Reference in New Issue
Block a user