2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-22 01:51:26 +00:00

ovsdb: Allow constraining the number of rows in a table.

This commit is contained in:
Ben Pfaff 2010-03-16 17:08:06 -07:00
parent 0cd85e1b0b
commit 87ab878cad
6 changed files with 91 additions and 7 deletions

View File

@ -101,6 +101,7 @@ is represented by <database-schema>, as described below.
A JSON object with the following members:
"columns": {<id>: <column-schema>, ...} required
"maxRows": <integer> optional
The value of "columns" is a JSON object whose names are column
names and whose values are <column-schema>s.
@ -122,6 +123,13 @@ is represented by <database-schema>, as described below.
the database process is stopped and then started again, each
"_version" also changes to a new random value.
If "maxRows" is specified, as a positive integer, it limits the
maximum number of rows that may be present in the table. This is
a "deferred" constraint, enforced only at transaction commit time
(see the "transact" request below). If "maxRows" is not
specified, the size of the table is limited only by the resources
available to the database server.
<column-schema>
A JSON object with the following members:
@ -362,6 +370,11 @@ include at least the following:
transaction), and this column is not allowed to be empty
because its <type> has a "min" of 1.
"error": "constraint violation"
The number of rows in a table exceeds the maximum number
permitted by the table's "maxRows" value (see <table-schema>).
If "params" contains one or more "wait" operations, then the
transaction may take an arbitrary amount of time to complete. The
database implementation must be capable of accepting, executing, and

View File

@ -18,6 +18,7 @@
#include "table.h"
#include <assert.h>
#include <limits.h>
#include "json.h"
#include "column.h"
@ -35,7 +36,8 @@ add_column(struct ovsdb_table_schema *ts, struct ovsdb_column *column)
}
struct ovsdb_table_schema *
ovsdb_table_schema_create(const char *name, bool mutable)
ovsdb_table_schema_create(const char *name, bool mutable,
unsigned int max_rows)
{
struct ovsdb_column *uuid, *version;
struct ovsdb_table_schema *ts;
@ -44,6 +46,7 @@ ovsdb_table_schema_create(const char *name, bool mutable)
ts->name = xstrdup(name);
ts->mutable = mutable;
shash_init(&ts->columns);
ts->max_rows = max_rows;
uuid = ovsdb_column_create("_uuid", false, true, &ovsdb_type_uuid);
add_column(ts, uuid);
@ -62,7 +65,7 @@ ovsdb_table_schema_clone(const struct ovsdb_table_schema *old)
struct ovsdb_table_schema *new;
struct shash_node *node;
new = ovsdb_table_schema_create(old->name, old->mutable);
new = ovsdb_table_schema_create(old->name, old->mutable, old->max_rows);
SHASH_FOR_EACH (node, &old->columns) {
const struct ovsdb_column *column = node->data;
@ -94,10 +97,11 @@ ovsdb_table_schema_from_json(const struct json *json, const char *name,
struct ovsdb_table_schema **tsp)
{
struct ovsdb_table_schema *ts;
const struct json *columns, *mutable;
const struct json *columns, *mutable, *max_rows;
struct shash_node *node;
struct ovsdb_parser parser;
struct ovsdb_error *error;
long long int n_max_rows;
*tsp = NULL;
@ -105,18 +109,31 @@ ovsdb_table_schema_from_json(const struct json *json, const char *name,
columns = ovsdb_parser_member(&parser, "columns", OP_OBJECT);
mutable = ovsdb_parser_member(&parser, "mutable",
OP_TRUE | OP_FALSE | OP_OPTIONAL);
max_rows = ovsdb_parser_member(&parser, "maxRows",
OP_INTEGER | OP_OPTIONAL);
error = ovsdb_parser_finish(&parser);
if (error) {
return error;
}
if (max_rows) {
if (json_integer(max_rows) <= 0) {
return ovsdb_syntax_error(json, NULL,
"maxRows must be at least 1");
}
n_max_rows = max_rows->u.integer;
} else {
n_max_rows = UINT_MAX;
}
if (shash_is_empty(json_object(columns))) {
return ovsdb_syntax_error(json, NULL,
"table must have at least one column");
}
ts = ovsdb_table_schema_create(name,
mutable ? json_boolean(mutable) : true);
mutable ? json_boolean(mutable) : true,
MIN(n_max_rows, UINT_MAX));
SHASH_FOR_EACH (node, json_object(columns)) {
struct ovsdb_column *column;
@ -160,6 +177,9 @@ ovsdb_table_schema_to_json(const struct ovsdb_table_schema *ts)
}
}
json_object_put(json, "columns", columns);
if (ts->max_rows != UINT_MAX) {
json_object_put(json, "maxRows", json_integer_create(ts->max_rows));
}
return json;
}

View File

@ -29,10 +29,12 @@ struct ovsdb_table_schema {
char *name;
bool mutable;
struct shash columns; /* Contains "struct ovsdb_column *"s. */
unsigned int max_rows; /* Maximum number of rows. */
};
struct ovsdb_table_schema *ovsdb_table_schema_create(const char *name,
bool mutable);
bool mutable,
unsigned int max_rows);
struct ovsdb_table_schema *ovsdb_table_schema_clone(
const struct ovsdb_table_schema *);
void ovsdb_table_schema_destroy(struct ovsdb_table_schema *);

View File

@ -441,6 +441,27 @@ determine_changes(struct ovsdb_txn *txn, struct ovsdb_txn_row *txn_row)
return NULL;
}
static struct ovsdb_error * WARN_UNUSED_RESULT
check_max_rows(struct ovsdb_txn *txn)
{
struct ovsdb_txn_table *t;
LIST_FOR_EACH (t, struct ovsdb_txn_table, node, &txn->txn_tables) {
size_t n_rows = hmap_count(&t->table->rows);
unsigned int max_rows = t->table->schema->max_rows;
if (n_rows > max_rows) {
return ovsdb_error("constraint violation",
"transaction causes \"%s\" table to contain "
"%zu rows, greater than the schema-defined "
"limit of %u row(s)",
t->table->schema->name, n_rows, max_rows);
}
}
return NULL;
}
struct ovsdb_error *
ovsdb_txn_commit(struct ovsdb_txn *txn, bool durable)
{
@ -459,6 +480,13 @@ ovsdb_txn_commit(struct ovsdb_txn *txn, bool durable)
return NULL;
}
/* Check maximum rows table constraints. */
error = check_max_rows(txn);
if (error) {
ovsdb_txn_abort(txn);
return error;
}
/* Update reference counts and check referential integrity. */
error = update_ref_counts(txn);
if (error) {

View File

@ -28,7 +28,8 @@ m4_define([CONSTRAINT_SCHEMA],
"constrained": {
"columns": {
"positive": {"type": {"key": {"type": "integer",
"minInteger": 1}}}}}}}]])
"minInteger": 1}}}},
"maxRows": 1}}}]])
m4_define([WEAK_SCHEMA],
[[{"name": "weak",
@ -462,10 +463,20 @@ OVSDB_CHECK_EXECUTION([insert and update constraints],
{"op": "update",
"table": "constrained",
"where": [],
"row": {"positive": -2}}]]]],
"row": {"positive": -2}}]]],
[[["constraints",
{"op": "insert",
"table": "constrained",
"row": {"positive": 1}}]]],
[[["constraints",
{"op": "insert",
"table": "constrained",
"row": {"positive": 2}}]]]],
[[[{"details":"0 is less than minimum allowed value 1","error":"constraint violation"}]
[{"details":"-1 is less than minimum allowed value 1","error":"constraint violation"}]
[{"details":"-2 is less than minimum allowed value 1","error":"constraint violation"}]
[{"uuid":["uuid","<0>"]}]
[{"uuid":["uuid","<1>"]},{"details":"transaction causes \"constrained\" table to contain 2 rows, greater than the schema-defined limit of 1 row(s)","error":"constraint violation"}]
]])
OVSDB_CHECK_EXECUTION([referential integrity -- simple],

View File

@ -10,6 +10,11 @@ OVSDB_CHECK_POSITIVE([immutable table with one column],
"mutable": false}']],
[[{"columns":{"name":{"type":"string"}},"mutable":false}]])
OVSDB_CHECK_POSITIVE([table with maxRows of 2],
[[parse-table mytable '{"columns": {"name": {"type": "string"}},
"maxRows": 2}']],
[[{"columns":{"name":{"type":"string"}},"maxRows":2}]])
OVSDB_CHECK_NEGATIVE([column names may not begin with _],
[[parse-table mytable \
'{"columns": {"_column": {"type": "integer"}}}']],
@ -23,3 +28,8 @@ OVSDB_CHECK_NEGATIVE([table must have at least one column (1)],
OVSDB_CHECK_NEGATIVE([table must have at least one column (2)],
[[parse-table mytable '{"columns": {}}']],
[[table must have at least one column]])
OVSDB_CHECK_NEGATIVE([table maxRows must be positive],
[[parse-table mytable '{"columns": {"name": {"type": "string"}},
"maxRows": 0}']],
[[syntax "{"columns":{"name":{"type":"string"}},"maxRows":0}": syntax error: maxRows must be at least 1]])