@@ -8,6 +8,7 @@ import sys
import ovs.json
import ovs.db.error
import ovs.db.schema
+from ovs.db.types import StringType, IntegerType, RealType
argv0 = sys.argv[0]
@@ -201,6 +202,26 @@ static inline bool %(s)s_is_deleted(const struct %(s)s *row)
return %(s)s_row_get_seqno(row, OVSDB_IDL_CHANGE_DELETE) > 0;
}
+void %(s)s_index_destroy_row(const struct %(s)s *);
+int %(s)s_index_compare(struct ovsdb_idl_index_cursor *, const struct %(s)s *, const struct %(s)s *);
+const struct %(s)s *%(s)s_index_first(struct ovsdb_idl_index_cursor *);
+const struct %(s)s *%(s)s_index_next(struct ovsdb_idl_index_cursor *);
+const struct %(s)s *%(s)s_index_find(struct ovsdb_idl_index_cursor *, const struct %(s)s *);
+const struct %(s)s *%(s)s_index_forward_to(struct ovsdb_idl_index_cursor *, const struct %(s)s *);
+const struct %(s)s *%(s)s_index_get_data(const struct ovsdb_idl_index_cursor *);
+#define %(S)s_FOR_EACH_RANGE(ROW, CURSOR, FROM, TO) \\
+ for ((ROW) = %(s)s_index_forward_to(CURSOR, FROM); \\
+ ((ROW) && %(s)s_index_compare(CURSOR, ROW, TO) <= 0); \\
+ (ROW) = %(s)s_index_next(CURSOR))
+#define %(S)s_FOR_EACH_EQUAL(ROW, CURSOR, KEY) \\
+ for ((ROW) = %(s)s_index_find(CURSOR, KEY); \\
+ ((ROW) && %(s)s_index_compare(CURSOR, ROW, KEY) == 0); \\
+ (ROW) = %(s)s_index_next(CURSOR))
+#define %(S)s_FOR_EACH_BYINDEX(ROW, CURSOR) \\
+ for ((ROW) = %(s)s_index_first(CURSOR); \\
+ (ROW); \\
+ (ROW) = %(s)s_index_next(CURSOR))
+
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 *);
@@ -257,6 +278,19 @@ bool %(s)s_is_updated(const struct %(s)s *, enum %(s)s_column_id);
print
# Table indexes.
+ print "struct %(s)s * %(s)s_index_init_row(struct ovsdb_idl*, const struct ovsdb_idl_table_class *);" % {'s': structName}
+ print
+ for columnName, column in sorted(table.columns.iteritems()):
+ print 'void %(s)s_index_set_%(c)s(const struct %(s)s *,' % {'s': structName, 'c': columnName},
+ if column.type.is_smap():
+ args = ['const struct smap *']
+ else:
+ comment, members = cMembers(prefix, tableName, columnName,
+ column, True)
+ args = ['%(type)s%(name)s' % member for member in members]
+ print '%s);' % ', '.join(args)
+
+ print
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:
@@ -979,6 +1013,231 @@ void
print " free(%s);" % var
print "}"
+# Index table related functions
+ print '''
+/* Destroy 'row' of kind "%(t)s". The row must have been
+ * created with ovsdb_idl_index_init_row.
+ */
+void
+%(s)s_index_destroy_row(const struct %(s)s *row)
+{
+ ovsdb_idl_index_destroy_row__(&row->header_);
+}
+ ''' % { 's' : structName, 't': tableName }
+ print """
+/* Creates a new row of kind "%(t)s". */
+struct %(s)s *
+%(s)s_index_init_row(struct ovsdb_idl* idl, const struct ovsdb_idl_table_class *class)
+{""" % {'s': structName, 't': tableName}
+ #for columnName, column in sorted(table.columns.iteritems()):
+ # if column.type.is_smap():
+ # print " smap_init(&row->%s);" % columnName
+ print " return (struct %(s)s *) ovsdb_idl_index_init_row(idl, class);" % {'s': structName, 't': tableName}
+ print "}"
+
+ print '''
+/* This function is used to compare "%(s)s" records on table in iteration loops for compound-index operations.
+ After been called, cursor point to current position in the index
+ Parameters: struct ovsdb_idl_index_cursor *cursor. Cursor used to iterate over the indexed data on this table.
+ const struct "%(s)s" *const_data1, const struct "%(s)s" *const_data2. Data to be compared.
+ Return value: 0 if both data values are equal, -1 if first parameter is less than second and 1 otherwise. */''' % {'s' : structName}
+ print 'int'
+ print '''%(s)s_index_compare(struct ovsdb_idl_index_cursor *cursor, const struct %(s)s *const_data1, const struct %(s)s *const_data2)
+{
+ struct %(s)s *data1 = CONST_CAST(struct %(s)s *, const_data1);
+ struct %(s)s *data2 = CONST_CAST(struct %(s)s *, const_data2);
+ return ovsdb_idl_index_compare(cursor, &data1->header_, &data2->header_);
+}''' % { 's' : structName }
+ print '''
+/* This function is called to position the cursor at the first row in "%(s)s" table on the associated compound-index.
+ Parameters: struct ovsdb_idl_index_cursor *cursor. Cursor used to iterate over the indexed data on this table.
+ Return value: The first row in the corresponding index. */''' % {'s' : structName }
+ print '''const struct %(s)s *\n%(s)s_index_first(struct ovsdb_idl_index_cursor *cursor)
+{
+ return %(s)s_cast(ovsdb_idl_index_first(cursor));
+}''' % { 's' : structName }
+ print '''
+/* This function is called to position the cursor at the next row in "%(s)s" table on the associated compound-index.
+ Parameters: struct ovsdb_idl_index_cursor *cursor. Cursor used to iterate over the indexed data on this table.
+ Return value: The next row in the corresponding index. */''' % {'s' : structName, 'c' : columnName }
+ print '''const struct %(s)s *\n%(s)s_index_next(struct ovsdb_idl_index_cursor *cursor)
+{
+ return %(s)s_cast(ovsdb_idl_index_next(cursor));
+}''' % { 's' : structName }
+ print '''
+/* This function is used to find the data of the row in "%(s)s" table that meet criteria with the requested data
+ associated in the compound-index.
+ Parameters: struct ovsdb_idl_index_cursor *cursor. Cursor used to iterate over the indexed data on this table.
+ const struct %(s)s *const_data. Data to be searched.
+ Return value: The row in the corresponding index if found or NULL otherwise. */''' % {'s' : structName }
+ print '''const struct %(s)s *\n%(s)s_index_find(struct ovsdb_idl_index_cursor *cursor, const struct %(s)s *const_data)
+{
+ struct %(s)s *data = CONST_CAST(struct %(s)s *, const_data);
+ return %(s)s_cast(ovsdb_idl_index_find(cursor, &data->header_));
+}''' % { 's' : structName }
+ print '''
+/* This function is used to set the cursor pointing to the row in "%(s)s" table that meet criteria of the requested data
+ associated in the compound-index.
+ Parameters: struct ovsdb_idl_index_cursor *cursor. Cursor used to iterate over the indexed data on this table.
+ const struct %(s)s *const_data. Data to be searched.
+ Return value: The row in the corresponding index closest to the criteria. */''' % {'s' : structName }
+ print '''const struct %(s)s *\n%(s)s_index_forward_to(struct ovsdb_idl_index_cursor *cursor, const struct %(s)s *const_data)
+{
+ struct %(s)s *data = CONST_CAST(struct %(s)s *, const_data);
+ return %(s)s_cast(ovsdb_idl_index_forward_to(cursor, &data->header_));
+}''' % { 's' : structName }
+ print '''
+/* This function is used to get the data of the row in the current position pointed by the cursor in
+ "%(s)s" table.
+ Parameters: struct ovsdb_idl_index_cursor *cursor. Cursor used to iterate over the indexed data on this table.
+ Return value: The row in the corresponding index if found or NULL otherwise. */''' % {'s' : structName, 'c' : columnName }
+ print '''const struct %(s)s *\n%(s)s_index_get_data(const struct ovsdb_idl_index_cursor *cursor)
+{
+ return %(s)s_cast(ovsdb_idl_index_data(CONST_CAST(struct ovsdb_idl_index_cursor*, cursor)));
+}''' % { 's' : structName }
+ # Indexes Set functions
+ for columnName, column in sorted(table.columns.iteritems()):
+ type = column.type
+
+ comment, members = cMembers(prefix, tableName, columnName,
+ column, True)
+
+ if type.is_smap():
+ print comment
+ print "//TODO: WRITE A REAL COMMENT!"
+ print """void
+%(s)s_index_set_%(c)s(const struct %(s)s *row, const struct smap *%(c)s)
+{
+ struct ovsdb_datum *datum = xmalloc(sizeof(struct ovsdb_datum));
+
+ if (%(c)s) {
+ struct smap_node *node;
+ size_t i;
+
+ datum->n = smap_count(%(c)s);
+ datum->keys = xmalloc(datum->n * sizeof *datum->keys);
+ datum->values = xmalloc(datum->n * sizeof *datum->values);
+
+ i = 0;
+ SMAP_FOR_EACH (node, %(c)s) {
+ datum->keys[i].string = xstrdup(node->key);
+ datum->values[i].string = xstrdup(node->value);
+ i++;
+ }
+ ovsdb_datum_sort_unique(datum, OVSDB_TYPE_STRING, OVSDB_TYPE_STRING);
+ } else {
+ ovsdb_datum_init_empty(datum);
+ }
+ ovsdb_idl_index_write_(CONST_CAST(struct ovsdb_idl_row *, &row->header_),
+ &%(s)s_columns[%(S)s_COL_%(C)s],
+ datum,
+ &%(p)stable_classes[%(P)sTABLE_%(T)s]);
+}
+""" % {'t': tableName,
+ 'p': prefix,
+ 'P': prefix.upper(),
+ 's': structName,
+ 'S': structName.upper(),
+ 'c': columnName,
+ 'C': columnName.upper(),
+ 't': tableName,
+ 'T': tableName.upper()}
+ continue
+
+ keyVar = members[0]['name']
+ nVar = None
+ valueVar = None
+ if type.value:
+ valueVar = members[1]['name']
+ if len(members) > 2:
+ nVar = members[2]['name']
+ else:
+ if len(members) > 1:
+ nVar = members[1]['name']
+
+ print comment
+ print 'void'
+ print '%(s)s_index_set_%(c)s(const struct %(s)s *row, %(args)s)' % \
+ {'s': structName, 'c': columnName,
+ 'args': ', '.join(['%(type)s%(name)s' % m for m in members])}
+ print "{"
+ print " struct ovsdb_datum *datum = xmalloc(sizeof(struct ovsdb_datum));"
+ if type.n_min == 1 and type.n_max == 1:
+ print " union ovsdb_atom *key = xmalloc(sizeof(union ovsdb_atom));"
+ if type.value:
+ print " union ovsdb_atom *value = xmalloc(sizeof(union ovsdb_atom));"
+ print
+ print " datum->n = 1;"
+ print " datum->keys = key;"
+ print " " + type.key.assign_c_value_casting_away_const("key->%s" % type.key.type.to_string(), keyVar)
+ if type.value:
+ print " datum->values = value;"
+ print " "+ type.value.assign_c_value_casting_away_const("value->%s" % type.value.type.to_string(), valueVar)
+ else:
+ print " datum->values = NULL;"
+ txn_write_func = "ovsdb_idl_index_write_"
+ elif type.is_optional_pointer():
+ print " union ovsdb_atom *key = xmalloc(sizeof (union ovsdb_atom));"
+ print
+ print " if (%s) {" % keyVar
+ print " datum->n = 1;"
+ print " datum->keys = key;"
+ print " " + type.key.assign_c_value_casting_away_const("key->%s" % type.key.type.to_string(), keyVar)
+ print " } else {"
+ print " datum->n = 0;"
+ print " datum->keys = NULL;"
+ print " }"
+ print " datum->values = NULL;"
+ txn_write_func = "ovsdb_idl_index_write_"
+ elif type.n_max == 1:
+ print " union ovsdb_atom *key = xmalloc(sizeof(union ovsdb_atom));"
+ print
+ print " if (%s) {" % nVar
+ print " datum->n = 1;"
+ print " datum->keys = key;"
+ print " " + type.key.assign_c_value_casting_away_const("key->%s" % type.key.type.to_string(), "*" + keyVar)
+ print " } else {"
+ print " datum->n = 0;"
+ print " datum->keys = NULL;"
+ print " }"
+ print " datum->values = NULL;"
+ txn_write_func = "ovsdb_idl_index_write_"
+ else:
+ print " size_t i;"
+ print
+ print " datum->n = %s;" % nVar
+ print " datum->keys = %s ? xmalloc(%s * sizeof *datum->keys) : NULL;" % (nVar, nVar)
+ if type.value:
+ print " datum->values = xmalloc(%s * sizeof *datum->values);" % nVar
+ else:
+ print " datum->values = NULL;"
+ print " for (i = 0; i < %s; i++) {" % nVar
+ print " " + type.key.copyCValue("datum->keys[i].%s" % type.key.type.to_string(), "%s[i]" % keyVar)
+ if type.value:
+ print " " + type.value.copyCValue("datum->values[i].%s" % type.value.type.to_string(), "%s[i]" % valueVar)
+ print " }"
+ if type.value:
+ valueType = type.value.toAtomicType()
+ else:
+ valueType = "OVSDB_TYPE_VOID"
+ print " ovsdb_datum_sort_unique(datum, %s, %s);" % (
+ type.key.toAtomicType(), valueType)
+ txn_write_func = "ovsdb_idl_index_write_"
+ print " %(f)s(CONST_CAST(struct ovsdb_idl_row *, &row->header_), &%(s)s_columns[ %(S)s_COL_%(C)s ], datum, &%(p)stable_classes[%(P)sTABLE_%(T)s]);" \
+ % {'f': txn_write_func,
+ 's': structName,
+ 'S': structName.upper(),
+ 'C': columnName.upper(),
+ 'p': prefix,
+ 'P': prefix.upper(),
+ 't': tableName,
+ 'T': tableName.upper()}
+ print "}"
+# End Index table related functions
+
+ # Table columns.
+ print "\nstruct ovsdb_idl_column %s_columns[%s_N_COLUMNS];" % (
+ structName, structName.upper())
print """
void
%(s)s_set_condition(struct ovsdb_idl *idl, struct ovsdb_idl_condition *condition)
@@ -1300,3 +1300,266 @@ OVSDB_CHECK_IDL_NOTIFY([simple idl verify notify],
014: i=1 r=123.5 b=false s=mystring u=<3> ia=[1 2 3] ra=[-0.5] ba=[true] sa=[abc def] ua=[<4> <5>] uuid=<0>
015: done
]])
+
+# Tests to verify the functionality of the one column compound index.
+# It tests index for one column string and integer indexes.
+# The run of test-ovsdb generates the output of the display of data using the different indexes defined in
+# the program.
+# Then, some at_checks are used to verify the correctness of the corresponding index as well as the existence
+# of all the rows involved in the test.
+m4_define([OVSDB_CHECK_IDL_COMPOUND_INDEX_SINGLE_COLUMN_C],
+ [AT_SETUP([$1 - C])
+ AT_KEYWORDS([ovsdb server idl compound_index_single_column compound_index positive $5])
+ AT_CHECK([ovsdb_start_idltest])
+ m4_if([$2], [], [],
+ [AT_CHECK([ovsdb-client transact unix:socket $2], [0], [ignore], [ignore], [kill `cat pid`])])
+# Generate the data to be tested.
+ AT_CHECK([test-ovsdb '-vPATTERN:console:test-ovsdb|%c|%m' -vjsonrpc -t10 -c idl-compound-index unix:socket $3],
+ [0], [stdout], [ignore], [kill `cat pid`])
+# Filter the rows of data that corresponds to the string index eliminating the extra columns of data.
+# This is done to verifiy that the output data is in the correct and expected order.
+ AT_CHECK([[cat stdout | grep -oh '[0-9]\{3\}: s=.*' | sed -e 's/ i=.*//g']],
+ [0], [$4], [], [kill `cat pid`])
+# Here, the data is filtered and sorted in order to have all the rows in the index and be
+# able to determined that all the involved rows are present.
+ AT_CHECK([[cat stdout | grep -oh '[0-9]\{3\}: s=.*' | sort -k 1,1n -k 2,2 -k 3,3]],
+ [0], [$5], [], [kill `cat pid`])
+# Filter the rows of data that corresponds to the integer index eliminating the extra columns of data.
+# This is done to verifiy that the output data is in the correct and expected order.
+ AT_CHECK([[cat stdout | grep -oh '[0-9]\{3\}: i=.*' | sed -e 's/ s=.*//g']],
+ [0], [$6], [], [kill `cat pid`])
+# Here again, the data is filtered and sorted in order to have all the rows in the index and be
+# able to determined that all the involved rows are present.
+ AT_CHECK([[cat stdout | grep -oh '[0-9]\{3\}: i=.*' | sort -k 1,1n -k 2,2 -k 3,3]],
+ [0], [$7], [], [kill `cat pid`])
+ OVSDB_SERVER_SHUTDOWN
+ AT_CLEANUP])
+
+OVSDB_CHECK_IDL_COMPOUND_INDEX_SINGLE_COLUMN_C([Compound_index, single column test ],
+ [['["idltest",
+ {"op": "insert", "table": "simple", "row": {"s":"List000", "i": 1, "b":true, "r":101.0}},
+ {"op": "insert", "table": "simple", "row": {"s":"List000", "i": 2, "b":false, "r":102.0}},
+ {"op": "insert", "table": "simple", "row": {"s":"List000", "i": 10, "b":true, "r":110.0}},
+ {"op": "insert", "table": "simple", "row": {"s":"List001", "i": 1, "b":false, "r":110.0}},
+ {"op": "insert", "table": "simple", "row": {"s":"List001", "i": 2, "b":true, "r":120.0}},
+ {"op": "insert", "table": "simple", "row": {"s":"List001", "i": 2, "b":true, "r":122.0}},
+ {"op": "insert", "table": "simple", "row": {"s":"List001", "i": 4, "b":true, "r":130.0}},
+ {"op": "insert", "table": "simple", "row": {"s":"List005", "i": 5, "b":true, "r":130.0}},
+ {"op": "insert", "table": "simple", "row": {"s":"List020", "i": 20, "b":true, "r":220.0}},
+ {"op": "insert", "table": "simple", "row": {"s":"List020", "i": 19, "b":true, "r":219.0}}
+ ]']],
+ [idl_compound_index_single_column],
+ [001: s=List000
+001: s=List000
+001: s=List000
+001: s=List001
+001: s=List001
+001: s=List001
+001: s=List001
+001: s=List005
+001: s=List020
+001: s=List020
+003: s=List001
+003: s=List001
+003: s=List001
+003: s=List001
+],
+[001: s=List000 i=1 b=True r=101.000000
+001: s=List000 i=10 b=True r=110.000000
+001: s=List000 i=2 b=False r=102.000000
+001: s=List001 i=1 b=False r=110.000000
+001: s=List001 i=2 b=True r=120.000000
+001: s=List001 i=2 b=True r=122.000000
+001: s=List001 i=4 b=True r=130.000000
+001: s=List005 i=5 b=True r=130.000000
+001: s=List020 i=19 b=True r=219.000000
+001: s=List020 i=20 b=True r=220.000000
+003: s=List001 i=1 b=False r=110.000000
+003: s=List001 i=2 b=True r=120.000000
+003: s=List001 i=2 b=True r=122.000000
+003: s=List001 i=4 b=True r=130.000000
+],
+[002: i=1
+002: i=1
+002: i=2
+002: i=2
+002: i=2
+002: i=4
+002: i=5
+002: i=10
+002: i=19
+002: i=20
+004: i=5
+005: i=4
+005: i=5
+006: i=5
+006: i=10
+006: i=19
+006: i=20
+006: i=54
+],
+[002: i=1 s=List000 b=True r=101.000000
+002: i=1 s=List001 b=False r=110.000000
+002: i=10 s=List000 b=True r=110.000000
+002: i=19 s=List020 b=True r=219.000000
+002: i=2 s=List000 b=False r=102.000000
+002: i=2 s=List001 b=True r=120.000000
+002: i=2 s=List001 b=True r=122.000000
+002: i=20 s=List020 b=True r=220.000000
+002: i=4 s=List001 b=True r=130.000000
+002: i=5 s=List005 b=True r=130.000000
+004: i=5 s=List005 b=True r=130.000000
+005: i=4 s=List001 b=True r=130.000000
+005: i=5 s=List005 b=True r=130.000000
+006: i=10 s=List000 b=True r=110.000000
+006: i=19 s=List020 b=True r=219.000000
+006: i=20 s=List020 b=True r=220.000000
+006: i=5 s=List005 b=True r=130.000000
+006: i=54 s=Lista054 b=False r=0.000000
+])
+
+# Tests to verify the functionality of two column compound index.
+# It tests index for two columns using string and integer fields.
+# The run of test-ovsdb generates the output of the display of data using the different indexes defined in
+# the program.
+# Then, some at_checks are used to verify the correctness of the corresponding index as well as the existence
+# of all the rows involved in the test.
+m4_define([OVSDB_CHECK_IDL_COMPOUND_INDEX_DOUBLE_COLUMN_C],
+ [AT_SETUP([$1 - C])
+ AT_KEYWORDS([ovsdb server idl compound_index_double_column compound_index positive $5])
+ AT_CHECK([ovsdb_start_idltest])
+ m4_if([$2], [], [],
+ [AT_CHECK([ovsdb-client transact unix:socket $2], [0], [ignore], [ignore], [kill `cat pid`])])
+# Generate the data to be tested.
+ AT_CHECK([test-ovsdb '-vPATTERN:console:test-ovsdb|%c|%m' -vjsonrpc -t10 -c idl-compound-index unix:socket $3],
+ [0], [stdout], [ignore], [kill `cat pid`])
+# Filter the rows of data that corresponds to the string-integer index eliminating the extra columns of data.
+# This is done to verifiy that the output data is in the correct and expected order.
+ AT_CHECK([[cat stdout | grep -oh '[0-9]\{3\}: s=.*' | sed -e 's/ b=.*//g']],
+ [0], [$4], [], [kill `cat pid`])
+# Here, the data is filtered and sorted in order to have all the rows in the index and be
+# able to determined that all the involved rows are present.
+ AT_CHECK([[cat stdout | grep -oh '[0-9]\{3\}: s=.*' | sort -k 1,1n -k 2,2 -k 3,3]],
+ [0], [$5], [], [kill `cat pid`])
+# Filter the rows of data that corresponds to the integer index eliminating the extra columns of data.
+# This is done to verifiy that the output data is in the correct and expected order.
+ AT_CHECK([[cat stdout | grep -oh '[0-9]\{3\}: i=.*' | sed -e 's/ b=.*//g']],
+ [0], [$6], [], [kill `cat pid`])
+# Here again, the data is filtered and sorted in order to have all the rows in the index and be
+# able to determined that all the involved rows are present.
+ AT_CHECK([[cat stdout | grep -oh '[0-9]\{3\}: i=.*' | sort -k 1,1n -k 2,2 -k 3,3]],
+ [0], [$7], [], [kill `cat pid`])
+ OVSDB_SERVER_SHUTDOWN
+ AT_CLEANUP])
+
+OVSDB_CHECK_IDL_COMPOUND_INDEX_DOUBLE_COLUMN_C([Compound_index, double column test ],
+ [['["idltest",
+ {"op": "insert", "table": "simple", "row": {"s":"List000", "i": 1, "b":true, "r":101.0}},
+ {"op": "insert", "table": "simple", "row": {"s":"List000", "i": 2, "b":false, "r":102.0}},
+ {"op": "insert", "table": "simple", "row": {"s":"List000", "i": 10, "b":true, "r":110.0}},
+ {"op": "insert", "table": "simple", "row": {"s":"List001", "i": 1, "b":false, "r":110.0}},
+ {"op": "insert", "table": "simple", "row": {"s":"List001", "i": 2, "b":true, "r":120.0}},
+ {"op": "insert", "table": "simple", "row": {"s":"List001", "i": 2, "b":true, "r":122.0}},
+ {"op": "insert", "table": "simple", "row": {"s":"List001", "i": 4, "b":true, "r":130.0}},
+ {"op": "insert", "table": "simple", "row": {"s":"List005", "i": 5, "b":true, "r":130.0}},
+ {"op": "insert", "table": "simple", "row": {"s":"List020", "i": 20, "b":true, "r":220.0}},
+ {"op": "insert", "table": "simple", "row": {"s":"List020", "i": 19, "b":true, "r":219.0}}
+ ]']],
+ [idl_compound_index_double_column],
+ [001: s=List000 i=1
+001: s=List000 i=2
+001: s=List000 i=10
+001: s=List001 i=1
+001: s=List001 i=2
+001: s=List001 i=2
+001: s=List001 i=4
+001: s=List005 i=5
+001: s=List020 i=19
+001: s=List020 i=20
+002: s=List000 i=10
+002: s=List000 i=2
+002: s=List000 i=1
+002: s=List001 i=4
+002: s=List001 i=2
+002: s=List001 i=2
+002: s=List001 i=1
+002: s=List005 i=5
+002: s=List020 i=20
+002: s=List020 i=19
+003: s=List000 i=10
+004: s=List001 i=1
+004: s=List001 i=2
+004: s=List001 i=2
+004: s=List001 i=4
+004: s=List005 i=5
+],
+ [001: s=List000 i=1 b=True r=101.000000
+001: s=List000 i=10 b=True r=110.000000
+001: s=List000 i=2 b=False r=102.000000
+001: s=List001 i=1 b=False r=110.000000
+001: s=List001 i=2 b=True r=120.000000
+001: s=List001 i=2 b=True r=122.000000
+001: s=List001 i=4 b=True r=130.000000
+001: s=List005 i=5 b=True r=130.000000
+001: s=List020 i=19 b=True r=219.000000
+001: s=List020 i=20 b=True r=220.000000
+002: s=List000 i=1 b=True r=101.000000
+002: s=List000 i=10 b=True r=110.000000
+002: s=List000 i=2 b=False r=102.000000
+002: s=List001 i=1 b=False r=110.000000
+002: s=List001 i=2 b=True r=120.000000
+002: s=List001 i=2 b=True r=122.000000
+002: s=List001 i=4 b=True r=130.000000
+002: s=List005 i=5 b=True r=130.000000
+002: s=List020 i=19 b=True r=219.000000
+002: s=List020 i=20 b=True r=220.000000
+003: s=List000 i=10 b=True r=110.000000
+004: s=List001 i=1 b=False r=110.000000
+004: s=List001 i=2 b=True r=120.000000
+004: s=List001 i=2 b=True r=122.000000
+004: s=List001 i=4 b=True r=130.000000
+004: s=List005 i=5 b=True r=130.000000
+],
+ [005: i=1 s=List000
+005: i=1 s=List001
+005: i=2 s=List000
+005: i=2 s=List001
+005: i=2 s=List001
+005: i=4 s=List001
+005: i=5 s=List005
+005: i=10 s=List000
+005: i=19 s=List020
+005: i=20 s=List020
+006: i=20 s=List020
+006: i=19 s=List020
+006: i=10 s=List000
+006: i=5 s=List005
+006: i=4 s=List001
+006: i=2 s=List000
+006: i=2 s=List001
+006: i=2 s=List001
+006: i=1 s=List000
+006: i=1 s=List001
+],
+ [005: i=1 s=List000 b=True r=101.000000
+005: i=1 s=List001 b=False r=110.000000
+005: i=10 s=List000 b=True r=110.000000
+005: i=19 s=List020 b=True r=219.000000
+005: i=2 s=List000 b=False r=102.000000
+005: i=2 s=List001 b=True r=120.000000
+005: i=2 s=List001 b=True r=122.000000
+005: i=20 s=List020 b=True r=220.000000
+005: i=4 s=List001 b=True r=130.000000
+005: i=5 s=List005 b=True r=130.000000
+006: i=1 s=List000 b=True r=101.000000
+006: i=1 s=List001 b=False r=110.000000
+006: i=10 s=List000 b=True r=110.000000
+006: i=19 s=List020 b=True r=219.000000
+006: i=2 s=List000 b=False r=102.000000
+006: i=2 s=List001 b=True r=120.000000
+006: i=2 s=List001 b=True r=122.000000
+006: i=20 s=List020 b=True r=220.000000
+006: i=4 s=List001 b=True r=130.000000
+006: i=5 s=List005 b=True r=130.000000
+])
+
@@ -215,7 +215,14 @@ usage(void)
" idl-partial-update-set-column SERVER \n"
" connect to SERVER and executes different operations to\n"
" test the capacity of updating elements inside a set column\n"
- " displaying the table information after each operation.\n",
+ " displaying the table information after each operation.\n"
+ " idl-compound-index TEST_TO_EXECUTE\n"
+ " Execute the tests to verify compound-index feature.\n"
+ " The TEST_TO_EXECUTE are:\n"
+ " idl_compound_index_single_column:\n"
+ " test for indexes using one column as part of the index.\n"
+ " idl_compound_index_double_column:\n"
+ " test for indexes using two columns as part of index.\n",
program_name, program_name);
vlog_usage();
printf("\nOther options:\n"
@@ -2635,6 +2642,236 @@ do_idl_partial_update_set_column(struct ovs_cmdl_context *ctx)
return;
}
+static int
+test_idl_compound_index_single_column(struct ovsdb_idl *idl,
+ struct ovsdb_idl_index_cursor* sCursor,
+ struct ovsdb_idl_index_cursor* iCursor)
+{
+ const struct idltest_simple* myRow;
+ struct ovsdb_idl_txn *txn;
+ int step=0;
+
+ /* Display records by string index -> sCursor */
+ ++step;
+ IDLTEST_SIMPLE_FOR_EACH_BYINDEX(myRow, sCursor)
+ {
+ printf("%03d: s=%s i=%"PRId64" b=%s r=%f\n", step, myRow->s, myRow->i, myRow->b?"True":"False", myRow->r);
+ }
+ /* Display records by integer index -> iCursor */
+ ++step;
+ IDLTEST_SIMPLE_FOR_EACH_BYINDEX(myRow, iCursor)
+ {
+ printf("%03d: i=%"PRId64" s=%s b=%s r=%f\n", step, myRow->i,myRow->s, myRow->b?"True":"False", myRow->r);
+ }
+ /* Display records by string index -> sCursor with filtering where s=\"List001\ */
+ ++step;
+ struct idltest_simple *equal = idltest_simple_index_init_row(idl, &idltest_table_simple);
+ idltest_simple_index_set_s(equal, "List001");
+ assert(strcmp(equal->s, "List001") == 0);
+ IDLTEST_SIMPLE_FOR_EACH_EQUAL(myRow, sCursor, equal)
+ {
+ printf("%03d: s=%s i=%"PRId64" b=%s r=%f\n", step, myRow->s, myRow->i, myRow->b?"True":"False", myRow->r);
+ }
+ /* Display records by integer index -> iCursor with filtering where i=5 */
+ ++step;
+ idltest_simple_index_set_i(equal, 5);
+ assert(equal->i == 5);
+ IDLTEST_SIMPLE_FOR_EACH_EQUAL(myRow, iCursor, equal) {
+ printf("%03d: i=%"PRId64" s=%s b=%s r=%f\n", step, myRow->i,myRow->s, myRow->b?"True":"False", myRow->r);
+ }
+ /* Display records by integer index -> iCursor in range i=[3,7] */
+ ++step;
+ struct idltest_simple *from, *to;
+ from = idltest_simple_index_init_row(idl, &idltest_table_simple);
+ idltest_simple_index_set_i(from, 3);
+ assert(from->i == 3);
+ to = idltest_simple_index_init_row(idl, &idltest_table_simple);
+ idltest_simple_index_set_i(to, 7);
+ assert(to->i == 7);
+ IDLTEST_SIMPLE_FOR_EACH_RANGE(myRow, iCursor, from, to)
+ {
+ printf("%03d: i=%"PRId64" s=%s b=%s r=%f\n", step, myRow->i,myRow->s, myRow->b?"True":"False", myRow->r);
+ }
+ /* Delete record i=4 and insert i=54 by integer index -> iCursor */
+ ++step;
+ struct idltest_simple *toDelete, *toInsert;
+ toDelete = idltest_simple_index_init_row(idl, &idltest_table_simple);
+ idltest_simple_index_set_i(toDelete, 4);
+ assert(toDelete->i == 4);
+ myRow = idltest_simple_index_find(iCursor, toDelete);
+ assert(myRow);
+ assert(myRow->i == 4);
+ txn = ovsdb_idl_txn_create(idl);
+ idltest_simple_delete(myRow);
+ toInsert = idltest_simple_insert(txn);
+ idltest_simple_set_i(toInsert, 54);
+ idltest_simple_set_s(toInsert, "Lista054");
+ ovsdb_idl_txn_commit_block(txn);
+ ovsdb_idl_txn_destroy(txn);
+ idltest_simple_index_set_i(to, 60);
+ printf("Expected 60, stored %"PRId64"\n", to->i);
+ assert(to->i == 60);
+ IDLTEST_SIMPLE_FOR_EACH_RANGE(myRow, iCursor, from, to)
+ {
+ printf("%03d: i=%"PRId64" s=%s b=%s r=%f\n", step, myRow->i, myRow->s, myRow->b?"True":"False", myRow->r);
+ }
+
+ /* Free the temporal rows */
+ idltest_simple_index_destroy_row(from);
+ idltest_simple_index_destroy_row(to);
+ idltest_simple_index_destroy_row(equal);
+ return step;
+}
+
+static int
+test_idl_compound_index_double_column(struct ovsdb_idl *idl,
+ struct ovsdb_idl_index_cursor* siCursor,
+ struct ovsdb_idl_index_cursor* sidCursor,
+ struct ovsdb_idl_index_cursor* isCursor,
+ struct ovsdb_idl_index_cursor* idsCursor)
+{
+ const struct idltest_simple* myRow;
+ int step = 0;
+
+ /* Display records by string-integer index -> siCursor */
+ step++;
+ IDLTEST_SIMPLE_FOR_EACH_BYINDEX(myRow, siCursor)
+ {
+ printf("%03d: s=%s i=%"PRId64" b=%s r=%f\n", step, myRow->s, myRow->i, myRow->b?"True":"False", myRow->r);
+ }
+ /* Display records by string-integer(down order) index -> sidCursor */
+ step++;
+ IDLTEST_SIMPLE_FOR_EACH_BYINDEX(myRow, sidCursor)
+ {
+ printf("%03d: s=%s i=%"PRId64" b=%s r=%f\n", step, myRow->s, myRow->i, myRow->b?"True":"False", myRow->r);
+ }
+ /* Display records by string-integer index -> siCursor with filtering where s="List000" and i=10 */
+ step++;
+ struct idltest_simple *equal = idltest_simple_index_init_row(idl, &idltest_table_simple);
+ idltest_simple_index_set_s(equal, "List000");
+ assert(strcmp(equal->s, "List000") == 0);
+ idltest_simple_index_set_i(equal, 10);
+ assert(equal->i == 10);
+ IDLTEST_SIMPLE_FOR_EACH_EQUAL(myRow, siCursor, equal)
+ {
+ printf("%03d: s=%s i=%"PRId64" b=%s r=%f\n", step, myRow->s, myRow->i, myRow->b?"True":"False", myRow->r);
+ }
+ /* Display records by string-integer index -> siCursor in range i=[0,100] and s=[\"List002\",\"List003\"] */
+ step++;
+ struct idltest_simple *from, *to;
+ from = idltest_simple_index_init_row(idl, &idltest_table_simple);
+ to = idltest_simple_index_init_row(idl, &idltest_table_simple);
+ idltest_simple_index_set_i(from, 0);
+ assert(from->i == 0);
+ idltest_simple_index_set_s(from, "List001");
+ assert(strcmp(from->s, "List001") == 0);
+ idltest_simple_index_set_i(to, 100);
+ assert(to->i == 100);
+ idltest_simple_index_set_s(to, "List005");
+ assert(strcmp(to->s, "List005")==0);
+ IDLTEST_SIMPLE_FOR_EACH_RANGE(myRow, siCursor, from, to)
+ {
+ printf("%03d: s=%s i=%"PRId64" b=%s r=%f\n", step, myRow->s, myRow->i, myRow->b?"True":"False", myRow->r);
+ }
+ /* Display records using integer-string index. */
+ step++;
+ IDLTEST_SIMPLE_FOR_EACH_BYINDEX(myRow, isCursor) {
+ printf("%03d: i=%"PRId64" s=%s b=%s r=%f\n", step, myRow->i, myRow->s, myRow->b?"True":"False", myRow->r);
+ }
+ /* Display records using integer(descend)-string index. */
+ step++;
+ IDLTEST_SIMPLE_FOR_EACH_BYINDEX(myRow, idsCursor) {
+ printf("%03d: i=%"PRId64" s=%s b=%s r=%f\n", step, myRow->i, myRow->s, myRow->b?"True":"False", myRow->r);
+ }
+
+ idltest_simple_index_destroy_row(to);
+ idltest_simple_index_destroy_row(from);
+ idltest_simple_index_destroy_row(equal);
+ return step;
+}
+
+static void
+do_idl_compound_index(struct ovs_cmdl_context *ctx)
+{
+ struct ovsdb_idl *idl;
+ struct ovsdb_idl_index_cursor sCursor, iCursor, siCursor, sidCursor,
+ isCursor, idsCursor;
+ enum TESTS { IDL_COMPOUND_INDEX_WITH_SINGLE_COLUMN,
+ IDL_COMPOUND_INDEX_WITH_DOUBLE_COLUMN
+ };
+ int step = 0;
+ int i;
+
+ idl = ovsdb_idl_create(ctx->argv[1], &idltest_idl_class, false, true);
+
+ /* Add tables/columns and initialize index data needed for tests */
+ ovsdb_idl_add_table(idl, &idltest_table_simple);
+ ovsdb_idl_add_column(idl, &idltest_simple_col_s);
+ ovsdb_idl_add_column(idl, &idltest_simple_col_i);
+ ovsdb_idl_add_column(idl, &idltest_simple_col_r);
+ ovsdb_idl_add_column(idl, &idltest_simple_col_b);
+
+ struct ovsdb_idl_index *index;
+ index = ovsdb_idl_create_index(idl, &idltest_table_simple, "string");
+ ovsdb_idl_index_add_column(index, &idltest_simple_col_s, OVSDB_INDEX_ASC, NULL);
+
+ index = ovsdb_idl_create_index(idl, &idltest_table_simple, "integer");
+ ovsdb_idl_index_add_column(index, &idltest_simple_col_i, OVSDB_INDEX_ASC, NULL);
+
+ index = ovsdb_idl_create_index(idl, &idltest_table_simple, "string-integer");
+ ovsdb_idl_index_add_column(index, &idltest_simple_col_s, OVSDB_INDEX_ASC, NULL);
+ ovsdb_idl_index_add_column(index, &idltest_simple_col_i, OVSDB_INDEX_ASC, NULL);
+
+ index = ovsdb_idl_create_index(idl, &idltest_table_simple, "string-integerd");
+ ovsdb_idl_index_add_column(index, &idltest_simple_col_s, OVSDB_INDEX_ASC, NULL);
+ ovsdb_idl_index_add_column(index, &idltest_simple_col_i, OVSDB_INDEX_DESC, NULL);
+
+ index = ovsdb_idl_create_index(idl, &idltest_table_simple, "integer-string");
+ ovsdb_idl_index_add_column(index, &idltest_simple_col_i, OVSDB_INDEX_ASC, NULL);
+ ovsdb_idl_index_add_column(index, &idltest_simple_col_s, OVSDB_INDEX_ASC, NULL);
+
+ index = ovsdb_idl_create_index(idl, &idltest_table_simple, "integerd-string");
+ ovsdb_idl_index_add_column(index, &idltest_simple_col_i, OVSDB_INDEX_DESC, NULL);
+ ovsdb_idl_index_add_column(index, &idltest_simple_col_s, OVSDB_INDEX_ASC, NULL);
+
+ /* wait for replica to be updated */
+ ovsdb_idl_get_initial_snapshot(idl);
+
+ /* Initialize cursors to be used by indexes */
+ ovsdb_idl_initialize_cursor(idl, &idltest_table_simple, "string", &sCursor);
+ ovsdb_idl_initialize_cursor(idl, &idltest_table_simple, "integer", &iCursor);
+ ovsdb_idl_initialize_cursor(idl, &idltest_table_simple, "string-integer", &siCursor);
+ ovsdb_idl_initialize_cursor(idl, &idltest_table_simple, "string-integerd", &sidCursor);
+ ovsdb_idl_initialize_cursor(idl, &idltest_table_simple, "integer-string", &isCursor);
+ ovsdb_idl_initialize_cursor(idl, &idltest_table_simple, "integerd-string", &idsCursor);
+
+ setvbuf(stdout, NULL, _IONBF, 0);
+ int test_to_run = -1;
+ for (i = 2; i < ctx->argc; i++) {
+ char *arg = ctx->argv[i];
+
+ if(strcmp(arg,"idl_compound_index_single_column")== 0) {
+ test_to_run = IDL_COMPOUND_INDEX_WITH_SINGLE_COLUMN;
+ } else if(strcmp(arg, "idl_compound_index_double_column")==0) {
+ test_to_run = IDL_COMPOUND_INDEX_WITH_DOUBLE_COLUMN;
+ }
+
+ switch(test_to_run) {
+ case IDL_COMPOUND_INDEX_WITH_SINGLE_COLUMN:
+ test_idl_compound_index_single_column(idl, &sCursor, &iCursor);
+ break;
+ case IDL_COMPOUND_INDEX_WITH_DOUBLE_COLUMN:
+ test_idl_compound_index_double_column(idl, &siCursor,
+ &sidCursor, &isCursor, &idsCursor);
+ break;
+ default:
+ printf("%03d: Test %s not implemented.\n", step++, arg);
+ }
+ }
+ ovsdb_idl_destroy(idl);
+ printf("%03d: done\n", step);
+}
+
static struct ovs_cmdl_command all_commands[] = {
{ "log-io", NULL, 2, INT_MAX, do_log_io, OVS_RO },
{ "default-atoms", NULL, 0, 0, do_default_atoms, OVS_RO },
@@ -2666,6 +2903,7 @@ static struct ovs_cmdl_command all_commands[] = {
{ "execute-readonly", NULL, 2, INT_MAX, do_execute_ro, OVS_RO },
{ "trigger", NULL, 2, INT_MAX, do_trigger, OVS_RO },
{ "idl", NULL, 1, INT_MAX, do_idl, OVS_RO },
+ { "idl-compound-index", NULL, 2, 2, do_idl_compound_index, OVS_RW },
{ "idl-partial-update-map-column", NULL, 1, INT_MAX,
do_idl_partial_update_map_column, OVS_RO },
{ "idl-partial-update-set-column", NULL, 1, INT_MAX,