Skip to content

Commit

Permalink
ovsdb-idl: Add support for column tracking in IDL.
Browse files Browse the repository at this point in the history
Recent IDL change tracking patches allow quick traversal of changed
rows. This patch adds additional support to track changed columns.
It allows an IDL client to efficiently check if a specific column
of a row was updated by IDL.

Signed-off-by: Shad Ansari <[email protected]>
Signed-off-by: Ben Pfaff <[email protected]>
  • Loading branch information
Shad Ansari authored and blp committed Jan 12, 2016
1 parent a82c384 commit 32d37ce
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 6 deletions.
4 changes: 3 additions & 1 deletion lib/ovsdb-idl-provider.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,10 @@ struct ovsdb_idl_row {
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 {
Expand Down
35 changes: 34 additions & 1 deletion lib/ovsdb-idl.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* 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.
Expand Down Expand Up @@ -775,6 +775,29 @@ ovsdb_idl_track_get_next(const struct ovsdb_idl_row *row)
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
Expand All @@ -792,6 +815,10 @@ ovsdb_idl_track_clear(const struct ovsdb_idl *idl)
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)) {
Expand Down Expand Up @@ -1257,6 +1284,7 @@ ovsdb_idl_row_apply_diff(struct ovsdb_idl_row *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;

Expand Down Expand Up @@ -1320,6 +1348,7 @@ ovsdb_idl_row_change__(struct ovsdb_idl_row *row, const struct json *row_json,
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;
Expand Down Expand Up @@ -1374,6 +1403,10 @@ ovsdb_idl_row_change__(struct ovsdb_idl_row *row, const struct json *row_json,
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 {
Expand Down
2 changes: 2 additions & 0 deletions lib/ovsdb-idl.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ void ovsdb_idl_track_add_all(struct ovsdb_idl *idl);
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 *);


Expand Down
15 changes: 11 additions & 4 deletions ovsdb/ovsdb-idlc.in
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ def printCIDLHeader(schemaFile):
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()])

Expand Down Expand Up @@ -189,6 +189,7 @@ const struct %(s)s *%(s)s_track_get_next(const struct %(s)s *);
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()):
Expand Down Expand Up @@ -217,7 +218,7 @@ struct %(s)s *%(s)s_insert(struct ovsdb_idl_txn *);
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])" % {
Expand All @@ -233,11 +234,11 @@ struct %(s)s *%(s)s_insert(struct ovsdb_idl_txn *);
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]
Expand Down Expand Up @@ -522,6 +523,12 @@ struct %(s)s *
%(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(),
Expand Down
11 changes: 11 additions & 0 deletions tests/ovsdb-idl.at
Original file line number Diff line number Diff line change
Expand Up @@ -688,9 +688,11 @@ OVSDB_CHECK_IDL_TRACK([track, simple idl, initially populated],
"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
]])

Expand Down Expand Up @@ -748,20 +750,29 @@ OVSDB_CHECK_IDL_TRACK([track, simple idl, initially empty, various ops],
[[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
]])
63 changes: 63 additions & 0 deletions tests/test-ovsdb.c
Original file line number Diff line number Diff line change
Expand Up @@ -1672,6 +1672,66 @@ compare_link1(const void *a_, const void *b_)
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)
{
Expand Down Expand Up @@ -1700,6 +1760,7 @@ 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
Expand All @@ -1724,6 +1785,7 @@ print_idl_row_link1(const struct idltest_link1 *l1, int step)
printf("%"PRId64, l1->l2->i);
}
printf(" uuid="UUID_FMT"\n", UUID_ARGS(&l1->header_.uuid));
print_idl_row_updated_link1(l1, step);
}

static void
Expand All @@ -1734,6 +1796,7 @@ print_idl_row_link2(const struct idltest_link2 *l2, int step)
printf("%"PRId64, l2->l1->i);
}
printf(" uuid="UUID_FMT"\n", UUID_ARGS(&l2->header_.uuid));
print_idl_row_updated_link2(l2, step);
}

static void
Expand Down

0 comments on commit 32d37ce

Please sign in to comment.