unsigned long int *written; /* Bitmap of columns from "new" to write. */
struct hmap_node txn_node; /* Node in ovsdb_idl_txn's list. */
+ /* Tracking data */
unsigned int change_seqno[OVSDB_IDL_CHANGE_MAX];
- struct ovs_list track_node;
+ struct ovs_list track_node; /* Rows modified/added/deleted by IDL */
+ unsigned long int *updated; /* Bitmap of columns updated by IDL */
};
struct ovsdb_idl_column {
-/* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
+/* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
return NULL;
}
+/* Returns true if a tracked 'column' in 'row' was updated by IDL, false
+ * otherwise. The tracking data is cleared by ovsdb_idl_track_clear()
+ *
+ * Function returns false if 'column' is not tracked (see
+ * ovsdb_idl_track_add_column()).
+ */
+bool
+ovsdb_idl_track_is_updated(const struct ovsdb_idl_row *row,
+ const struct ovsdb_idl_column *column)
+{
+ const struct ovsdb_idl_table_class *class;
+ size_t column_idx;
+
+ class = row->table->class;
+ column_idx = column - class->columns;
+
+ if (row->updated && bitmap_is_set(row->updated, column_idx)) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
/* Flushes the tracked rows. Client calls this function after calling
* ovsdb_idl_run() and read all tracked rows with the ovsdb_idl_track_get_*()
* functions. This is usually done at the end of the client's processing
struct ovsdb_idl_row *row, *next;
LIST_FOR_EACH_SAFE(row, next, track_node, &table->track_list) {
+ if (row->updated) {
+ free(row->updated);
+ row->updated = NULL;
+ }
list_remove(&row->track_node);
list_init(&row->track_node);
if (ovsdb_idl_row_is_orphan(row)) {
const struct json *diff_json)
{
struct ovsdb_idl_table *table = row->table;
+ const struct ovsdb_idl_table_class *class = table->class;
struct shash_node *node;
bool changed = false;
enum ovsdb_idl_change change)
{
struct ovsdb_idl_table *table = row->table;
+ const struct ovsdb_idl_table_class *class = table->class;
struct shash_node *node;
bool changed = false;
bool apply_diff = diff_json != NULL;
list_push_front(&row->table->track_list,
&row->track_node);
}
+ if (!row->updated) {
+ row->updated = bitmap_allocate(class->n_columns);
+ }
+ bitmap_set1(row->updated, column_idx);
}
}
} else {
const struct ovsdb_idl_row *ovsdb_idl_track_get_first(
const struct ovsdb_idl *, const struct ovsdb_idl_table_class *);
const struct ovsdb_idl_row *ovsdb_idl_track_get_next(const struct ovsdb_idl_row *);
+bool ovsdb_idl_track_is_updated(const struct ovsdb_idl_row *row,
+ const struct ovsdb_idl_column *column);
void ovsdb_idl_track_clear(const struct ovsdb_idl *);
\f
print "};"
# Column indexes.
- printEnum(["%s_COL_%s" % (structName.upper(), columnName.upper())
+ printEnum("%s_column_id" % structName.lower(), ["%s_COL_%s" % (structName.upper(), columnName.upper())
for columnName in sorted(table.columns)]
+ ["%s_N_COLUMNS" % structName.upper()])
void %(s)s_init(struct %(s)s *);
void %(s)s_delete(const struct %(s)s *);
struct %(s)s *%(s)s_insert(struct ovsdb_idl_txn *);
+bool %(s)s_is_updated(const struct %(s)s *, enum %(s)s_column_id);
''' % {'s': structName, 'S': structName.upper()}
for columnName, column in sorted(table.columns.iteritems()):
print
# Table indexes.
- printEnum(["%sTABLE_%s" % (prefix.upper(), tableName.upper()) for tableName in sorted(schema.tables)] + ["%sN_TABLES" % prefix.upper()])
+ printEnum("%stable_id" % prefix.lower(), ["%sTABLE_%s" % (prefix.upper(), tableName.upper()) for tableName in sorted(schema.tables)] + ["%sN_TABLES" % prefix.upper()])
print
for tableName in schema.tables:
print "#define %(p)stable_%(t)s (%(p)stable_classes[%(P)sTABLE_%(T)s])" % {
print "\nconst char * %sget_db_version(void);" % prefix
print "\n#endif /* %(prefix)sIDL_HEADER */" % {'prefix': prefix.upper()}
-def printEnum(members):
+def printEnum(type, members):
if len(members) == 0:
return
- print "\nenum {";
+ print "\nenum %s {" % type
for member in members[:-1]:
print " %s," % member
print " %s" % members[-1]
%(s)s_insert(struct ovsdb_idl_txn *txn)
{
return %(s)s_cast(ovsdb_idl_txn_insert(txn, &%(p)stable_classes[%(P)sTABLE_%(T)s], NULL));
+}
+
+bool
+%(s)s_is_updated(const struct %(s)s *row, enum %(s)s_column_id column)
+{
+ return ovsdb_idl_track_is_updated(&row->header_, &%(s)s_columns[column]);
}''' % {'s': structName,
'p': prefix,
'P': prefix.upper(),
"where": [],
"row": {"b": true}}]']],
[[000: i=1 r=2 b=true s=mystring u=<0> ia=[1 2 3] ra=[-0.5] ba=[true] sa=[abc def] ua=[<1> <2>] uuid=<3>
+000: updated columns: b ba i ia r ra s sa u ua
001: {"error":null,"result":[{"count":2}]}
002: i=0 r=0 b=true s= u=<4> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<5>
002: i=1 r=2 b=true s=mystring u=<0> ia=[1 2 3] ra=[-0.5] ba=[true] sa=[abc def] ua=[<1> <2>] uuid=<3>
+002: updated columns: b
003: done
]])
[[000: empty
001: {"error":null,"result":[{"uuid":["uuid","<0>"]},{"uuid":["uuid","<1>"]}]}
002: i=1 r=2 b=true s=mystring u=<2> ia=[1 2 3] ra=[-0.5] ba=[true] sa=[abc def] ua=[<3> <4>] uuid=<0>
+002: updated columns: b ba i ia r ra s sa u ua
003: {"error":null,"result":[{"count":2}]}
004: i=0 r=0 b=true s= u=<5> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
+004: updated columns: b
005: {"error":null,"result":[{"count":2}]}
006: i=0 r=123.5 b=true s= u=<5> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
006: i=1 r=123.5 b=true s=mystring u=<2> ia=[1 2 3] ra=[-0.5] ba=[true] sa=[abc def] ua=[<3> <4>] uuid=<0>
+006: updated columns: r
+006: updated columns: r
007: {"error":null,"result":[{"uuid":["uuid","<6>"]}]}
008: i=-1 r=125 b=false s= u=<5> ia=[1] ra=[1.5] ba=[false] sa=[] ua=[] uuid=<6>
+008: updated columns: ba i ia r ra
009: {"error":null,"result":[{"count":2}]}
010: i=-1 r=125 b=false s=newstring u=<5> ia=[1] ra=[1.5] ba=[false] sa=[] ua=[] uuid=<6>
010: i=0 r=123.5 b=true s=newstring u=<5> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
+010: updated columns: s
+010: updated columns: s
011: {"error":null,"result":[{"count":1}]}
012: ##deleted## uuid=<1>
013: reconnect
014: i=-1 r=125 b=false s=newstring u=<5> ia=[1] ra=[1.5] ba=[false] sa=[] ua=[] uuid=<6>
014: i=1 r=123.5 b=true s=mystring u=<2> ia=[1 2 3] ra=[-0.5] ba=[true] sa=[abc def] ua=[<3> <4>] uuid=<0>
+014: updated columns: b ba i ia r ra s sa u ua
+014: updated columns: ba i ia r ra s
015: done
]])
return a->i < b->i ? -1 : a->i > b->i;
}
+static void
+print_idl_row_updated_simple(const struct idltest_simple *s, int step)
+{
+ size_t i;
+ bool updated = false;
+
+ for (i = 0; i < IDLTEST_SIMPLE_N_COLUMNS; i++) {
+ if (idltest_simple_is_updated(s, i)) {
+ if (!updated) {
+ printf("%03d: updated columns:", step);
+ updated = true;
+ }
+ printf(" %s", idltest_simple_columns[i].name);
+ }
+ }
+ if (updated) {
+ printf("\n");
+ }
+}
+
+static void
+print_idl_row_updated_link1(const struct idltest_link1 *l1, int step)
+{
+ size_t i;
+ bool updated = false;
+
+ for (i = 0; i < IDLTEST_LINK1_N_COLUMNS; i++) {
+ if (idltest_link1_is_updated(l1, i)) {
+ if (!updated) {
+ printf("%03d: updated columns:", step);
+ updated = true;
+ }
+ printf(" %s", idltest_link1_columns[i].name);
+ }
+ }
+ if (updated) {
+ printf("\n");
+ }
+}
+
+static void
+print_idl_row_updated_link2(const struct idltest_link2 *l2, int step)
+{
+ size_t i;
+ bool updated = false;
+
+ for (i = 0; i < IDLTEST_LINK2_N_COLUMNS; i++) {
+ if (idltest_link2_is_updated(l2, i)) {
+ if (!updated) {
+ printf("%03d: updated columns:", step);
+ updated = true;
+ }
+ printf(" %s", idltest_link2_columns[i].name);
+ }
+ }
+ if (updated) {
+ printf("\n");
+ }
+}
+
static void
print_idl_row_simple(const struct idltest_simple *s, int step)
{
printf("%s"UUID_FMT, i ? " " : "", UUID_ARGS(&s->ua[i]));
}
printf("] uuid="UUID_FMT"\n", UUID_ARGS(&s->header_.uuid));
+ print_idl_row_updated_simple(s, step);
}
static void
printf("%"PRId64, l1->l2->i);
}
printf(" uuid="UUID_FMT"\n", UUID_ARGS(&l1->header_.uuid));
+ print_idl_row_updated_link1(l1, step);
}
static void
printf("%"PRId64, l2->l1->i);
}
printf(" uuid="UUID_FMT"\n", UUID_ARGS(&l2->header_.uuid));
+ print_idl_row_updated_link2(l2, step);
}
static void