This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Tarantool -- an efficient key/value data store".
The branch box-namespace_limit has been created
at eade0287f8c53c3d490172af0ec44409d68750f8 (commit)
commit eade0287f8c53c3d490172af0ec44409d68750f8
Author: Roman Tokarev <[email protected]>
Date: Wed Apr 13 12:49:18 2011 +0400
Blueprint: 'Limit the total amount of memory consumed by a namespace'
https://blueprints.launchpad.net/tarantool/+spec/namespace-limits
Limit the total amount of memory consumed by a namespace.
If the limit is exceeded, freeze the namespace and do not accept
updates until data is deleted.
diff --git a/cfg/tarantool_box_cfg.c b/cfg/tarantool_box_cfg.c
index deea203..5e2aab9 100644
--- a/cfg/tarantool_box_cfg.c
+++ b/cfg/tarantool_box_cfg.c
@@ -73,6 +73,7 @@ acceptDefault_name__namespace(tarantool_cfg_namespace *c) {
c->enabled = -1;
c->cardinality = -1;
c->estimated_rows = 0;
+ c->limit = 0;
c->index = NULL;
return 0;
}
@@ -214,6 +215,10 @@ static NameAtom _name__namespace__estimated_rows[] = {
{ "namespace", -1, _name__namespace__estimated_rows + 1 },
{ "estimated_rows", -1, NULL }
};
+static NameAtom _name__namespace__limit[] = {
+ { "namespace", -1, _name__namespace__limit + 1 },
+ { "limit", -1, NULL }
+};
static NameAtom _name__namespace__index[] = {
{ "namespace", -1, _name__namespace__index + 1 },
{ "index", -1, NULL }
@@ -780,6 +785,20 @@ acceptValue(tarantool_cfg* c, OptDef* opt, int
check_rdonly) {
return CNF_RDONLY;
c->namespace[opt->name->index]->estimated_rows = i32;
}
+ else if ( cmpNameAtoms( opt->name, _name__namespace__limit) ) {
+ if (opt->paramType != numberType )
+ return CNF_WRONGTYPE;
+ ARRAYALLOC(c->namespace, opt->name->index + 1,
_name__namespace, check_rdonly, CNF_FLAG_STRUCT_NEW | CNF_FLAG_STRUCT_NOTSET);
+ if (c->namespace[opt->name->index]->__confetti_flags &
CNF_FLAG_STRUCT_NEW)
+ check_rdonly = 0;
+ c->namespace[opt->name->index]->__confetti_flags &=
~CNF_FLAG_STRUCT_NOTSET;
+ c->namespace[opt->name->index]->__confetti_flags &=
~CNF_FLAG_STRUCT_NOTSET;
+ errno = 0;
+ double dbl = strtod(opt->paramValue.numberval, NULL);
+ if ( (dbl == 0 || dbl == -HUGE_VAL || dbl == HUGE_VAL) && errno
== ERANGE)
+ return CNF_WRONGRANGE;
+ c->namespace[opt->name->index]->limit = dbl;
+ }
else if ( cmpNameAtoms( opt->name, _name__namespace__index) ) {
if (opt->paramType != arrayType )
return CNF_WRONGTYPE;
@@ -1036,6 +1055,7 @@ typedef enum IteratorState {
S_name__namespace__enabled,
S_name__namespace__cardinality,
S_name__namespace__estimated_rows,
+ S_name__namespace__limit,
S_name__namespace__index,
S_name__namespace__index__type,
S_name__namespace__index__unique,
@@ -1451,6 +1471,7 @@ again:
case S_name__namespace__enabled:
case S_name__namespace__cardinality:
case S_name__namespace__estimated_rows:
+ case S_name__namespace__limit:
case S_name__namespace__index:
case S_name__namespace__index__type:
case S_name__namespace__index__unique:
@@ -1491,6 +1512,17 @@ again:
}
sprintf(*v, "%"PRId32,
c->namespace[i->idx_name__namespace]->estimated_rows);
snprintf(buf, PRINTBUFLEN-1,
"namespace[%d].estimated_rows", i->idx_name__namespace);
+ i->state =
S_name__namespace__limit;
+ return buf;
+ case S_name__namespace__limit:
+ *v = malloc(32);
+ if (*v == NULL) {
+ free(i);
+
out_warning(CNF_NOMEMORY, "No memory to output value");
+ return NULL;
+ }
+ sprintf(*v, "%g",
c->namespace[i->idx_name__namespace]->limit);
+ snprintf(buf, PRINTBUFLEN-1,
"namespace[%d].limit", i->idx_name__namespace);
i->state =
S_name__namespace__index;
return buf;
case S_name__namespace__index:
@@ -1789,6 +1821,7 @@ dup_tarantool_cfg(tarantool_cfg* dst, tarantool_cfg* src)
{
dst->namespace[i->idx_name__namespace]->enabled =
src->namespace[i->idx_name__namespace]->enabled;
dst->namespace[i->idx_name__namespace]->cardinality =
src->namespace[i->idx_name__namespace]->cardinality;
dst->namespace[i->idx_name__namespace]->estimated_rows
= src->namespace[i->idx_name__namespace]->estimated_rows;
+ dst->namespace[i->idx_name__namespace]->limit =
src->namespace[i->idx_name__namespace]->limit;
dst->namespace[i->idx_name__namespace]->index = NULL;
if (src->namespace[i->idx_name__namespace]->index !=
NULL) {
@@ -2118,6 +2151,13 @@ cmp_tarantool_cfg(tarantool_cfg* c1, tarantool_cfg* c2,
int only_check_rdonly) {
return diff;
}
+ if (!only_check_rdonly) {
+ if (c1->namespace[i1->idx_name__namespace]->limit !=
c2->namespace[i2->idx_name__namespace]->limit) {
+ snprintf(diff, PRINTBUFLEN - 1, "%s",
"c->namespace[]->limit");
+
+ return diff;
+ }
+ }
i1->idx_name__namespace__index = 0;
i2->idx_name__namespace__index = 0;
diff --git a/cfg/tarantool_box_cfg.cfg b/cfg/tarantool_box_cfg.cfg
index a107365..51f8a30 100644
--- a/cfg/tarantool_box_cfg.cfg
+++ b/cfg/tarantool_box_cfg.cfg
@@ -110,6 +110,9 @@ namespace = [ {
enabled = -1
cardinality = -1
estimated_rows = 0
+
+ # Namespace limit in MBytes (0 stands for unlimited)
+ limit = 0
index = [ {
type = ""
unique = -1
diff --git a/cfg/tarantool_box_cfg.h b/cfg/tarantool_box_cfg.h
index 19d130b..4357291 100644
--- a/cfg/tarantool_box_cfg.h
+++ b/cfg/tarantool_box_cfg.h
@@ -29,6 +29,9 @@ typedef struct tarantool_cfg_namespace {
int32_t enabled;
int32_t cardinality;
int32_t estimated_rows;
+
+ /* Namespace limit in MBytes (0 stands for unlimited) */
+ double limit;
tarantool_cfg_namespace_index** index;
} tarantool_cfg_namespace;
diff --git a/include/iproto.h b/include/iproto.h
index 2d9b55e..ee897c1 100644
--- a/include/iproto.h
+++ b/include/iproto.h
@@ -90,7 +90,8 @@ void iproto_interact(void *);
_(ERR_CODE_NODE_NOT_FOUND, 0x00003102) \
_(ERR_CODE_NODE_FOUND, 0x00003702) \
_(ERR_CODE_INDEX_VIOLATION, 0x00003802) \
- _(ERR_CODE_NO_SUCH_NAMESPACE, 0x00003902)
+ _(ERR_CODE_NO_SUCH_NAMESPACE, 0x00003902) \
+ _(ERR_CODE_NAMESPACE_LIMIT, 0x00003a02) /* namespace limit is
exceeded */
ENUM(error_codes, ERROR_CODES);
extern char *error_codes_strs[];
diff --git a/mod/box/box.h b/mod/box/box.h
index b68c613..01bcf47 100644
--- a/mod/box/box.h
+++ b/mod/box/box.h
@@ -26,8 +26,11 @@
* SUCH DAMAGE.
*/
-#include <mod/box/index.h>
+#include <cfg/warning.h>
#include <exceptions.h>
+#include <iproto.h>
+#include <mod/box/index.h>
+#include <say.h>
#include <tbuf.h>
@interface tnt_BoxException: tnt_Exception {
@@ -55,6 +58,9 @@ struct namespace {
bool enabled;
int cardinality;
struct index index[MAX_IDX];
+
+ size_t usage;
+ size_t limit;
};
extern struct namespace *namespace;
@@ -68,6 +74,8 @@ struct box_tuple {
u8 data[0];
} __attribute__((packed));
+#define SIZEOF_TUPLE(tuple) (sizeof(struct box_tuple) + (tuple)->bsize)
+
struct box_txn {
u16 op;
u32 flags;
@@ -138,6 +146,24 @@ enum box_mode {
ENUM(messages, MESSAGES);
+static void __attribute__((unused, always_inline))
+tnt_namespace_update_usage(struct namespace *namespace, ssize_t bytes)
+{
+ say_debug("usage = %zu limit = %zu bytes = %zi", namespace->usage,
namespace->limit, bytes);
+
+ if (bytes < 0)
+ assert(namespace->usage >= -bytes);
+ else
+ assert(namespace->usage <= SIZE_MAX - bytes);
+ namespace->usage += bytes;
+
+ if (namespace->usage > namespace->limit)
+ if (bytes > 0) {
+ tnt_raise(tnt_BoxException, reason:"namespace limit is
exceeded"
+
errcode:ERR_CODE_NAMESPACE_LIMIT);
+ }
+}
+
struct box_txn *txn_alloc(u32 flags);
u32 box_process(struct box_txn *txn, u32 op, struct tbuf *request_data);
diff --git a/mod/box/box.m b/mod/box/box.m
index 7391ffc..124b0d3 100644
--- a/mod/box/box.m
+++ b/mod/box/box.m
@@ -232,7 +232,7 @@ tuple_free(struct box_tuple *tuple)
}
static void
-tuple_ref(struct box_tuple *tuple, int count)
+tuple_ref(struct box_txn *txn, struct box_tuple *tuple, int count)
{
assert(tuple->refs + count >= 0);
tuple->refs += count;
@@ -240,8 +240,10 @@ tuple_ref(struct box_tuple *tuple, int count)
if (tuple->refs > 0)
tuple->flags &= ~NEW;
- if (tuple->refs == 0)
+ if (tuple->refs == 0) {
+ tnt_namespace_update_usage(&namespace[txn->n],
-SIZEOF_TUPLE(tuple));
tuple_free(tuple);
+ }
}
void
@@ -249,7 +251,7 @@ tuple_txn_ref(struct box_txn *txn, struct box_tuple *tuple)
{
say_debug("tuple_txn_ref(%p)", tuple);
tbuf_append(txn->ref_tuples, &tuple, sizeof(struct box_tuple *));
- tuple_ref(tuple, +1);
+ tuple_ref(txn, tuple, +1);
}
static void __attribute__((noinline))
@@ -265,6 +267,7 @@ prepare_replace(struct box_txn *txn, size_t cardinality,
struct tbuf *data)
txn->tuple = tuple_alloc(data->len);
tuple_txn_ref(txn, txn->tuple);
+ tnt_namespace_update_usage(&namespace[txn->n],
SIZEOF_TUPLE(txn->tuple));
txn->tuple->cardinality = cardinality;
memcpy(txn->tuple->data, data->data, data->len);
@@ -333,12 +336,12 @@ commit_replace(struct box_txn *txn)
foreach_index(txn->n, index)
index->replace(index, txn->old_tuple, txn->tuple);
- tuple_ref(txn->old_tuple, -1);
+ tuple_ref(txn, txn->old_tuple, -1);
}
if (txn->tuple != NULL) {
txn->tuple->flags &= ~GHOST;
- tuple_ref(txn->tuple, +1);
+ tuple_ref(txn, txn->tuple, +1);
}
}
@@ -565,6 +568,7 @@ prepare_update_fields(struct box_txn *txn, struct tbuf
*data)
bsize += fields[i]->len + varint32_sizeof(fields[i]->len);
txn->tuple = tuple_alloc(bsize);
tuple_txn_ref(txn, txn->tuple);
+ tnt_namespace_update_usage(&namespace[txn->n],
SIZEOF_TUPLE(txn->tuple));
txn->tuple->cardinality = txn->old_tuple->cardinality;
uint8_t *p = txn->tuple->data;
@@ -720,7 +724,7 @@ commit_delete(struct box_txn *txn)
foreach_index(txn->n, index)
index->remove(index, txn->old_tuple);
- tuple_ref(txn->old_tuple, -1);
+ tuple_ref(txn, txn->old_tuple, -1);
}
static bool
@@ -791,7 +795,7 @@ txn_cleanup(struct box_txn *txn)
while (i-- > 0) {
say_debug("tuple_txn_unref(%p)", *tuple);
- tuple_ref(*tuple++, -1);
+ tuple_ref(txn, *tuple++, -1);
}
/* mark txn as clean */
@@ -1081,6 +1085,10 @@ custom_init(void)
namespace[i].cardinality = cfg.namespace[i]->cardinality;
int estimated_rows = cfg.namespace[i]->estimated_rows;
+ namespace[i].limit = cfg.namespace[i]->limit == 0. ?
+ SIZE_MAX :
+ cfg.namespace[i]->limit * (1 << 20);
+
if (cfg.namespace[i]->index == NULL)
panic("(namespace = %" PRIu32 ") at least one index
must be defined", i);
@@ -1206,7 +1214,16 @@ box_process(struct box_txn *txn, u32 op, struct tbuf
*request_data)
@try {
txn_begin(txn, op, request_data);
box_dispach(txn, request_data);
- txn_commit(txn);
+ /*
+ * Verify that there isn't any exception during txn_commit.
+ * Panic if one has happened.
+ */
+ @try {
+ txn_commit(txn);
+ }
+ @catch (id e) {
+ panic("exception `%s' during txn_commit", [e name]);
+ }
return ERR_CODE_OK;
}
@@ -1359,15 +1376,56 @@ memcached_bound_to_primary(void *data
__attribute__((unused)))
}
i32
-mod_check_config(struct tarantool_cfg *conf __attribute__((unused)))
+mod_check_config(struct tarantool_cfg *conf)
{
+ if (!namespace)
+ return 0;
+
+ for (u32 i = 0; i < namespace_count; i++) {
+ size_t new_limit;
+
+ if (conf->namespace[i] == NULL)
+ break;
+
+ if (!CNF_STRUCT_DEFINED(conf->namespace[i]))
+ continue;
+
+ if (!namespace[i].enabled)
+ continue;
+
+ new_limit = conf->namespace[i]->limit == 0 ?
+ SIZE_MAX :
+ conf->namespace[i]->limit * (1 << 20);
+ if (namespace[i].usage > new_limit) {
+ out_warning(0, "Could not change namespace[%u] limit: "
+ "it's lower than current namespace
usage", i);
+
+ return -1;
+ }
+ }
+
return 0;
}
void
mod_reload_config(struct tarantool_cfg *old_conf __attribute__((unused)),
- struct tarantool_cfg *new_conf __attribute__((unused)))
+ struct tarantool_cfg *new_conf)
{
+ for (u32 i = 0; i < namespace_count; i++) {
+ if (new_conf->namespace[i] == NULL)
+ break;
+
+ if (!CNF_STRUCT_DEFINED(new_conf->namespace[i]))
+ continue;
+
+ if (!namespace[i].enabled)
+ continue;
+
+ namespace[i].limit= new_conf->namespace[i]->limit == 0 ?
+ SIZE_MAX :
+ new_conf->namespace[i]->limit * (1 << 20);
+ }
+
return;
}
@@ -1379,6 +1437,7 @@ mod_init(void)
namespace = palloc(eter_pool, sizeof(struct namespace) *
namespace_count);
for (int i = 0; i < namespace_count; i++) {
namespace[i].enabled = false;
+ namespace[i].usage = 0;
for (int j = 0; j < MAX_IDX; j++)
namespace[i].index[j].key_cardinality = 0;
}
@@ -1534,6 +1593,15 @@ mod_info(struct tbuf *out)
tbuf_printf(out, " recovery_last_update: %.3f" CRLF,
recovery_state->recovery_last_update_tstamp);
tbuf_printf(out, " status: %s" CRLF, status);
+
+ tbuf_printf(out, " namespace_stat:" CRLF);
+ for (u32 i = 0; i < namespace_count; ++i) {
+ if (!namespace[i].enabled)
+ continue;
+
+ tbuf_printf(out, " namespace_%u:" CRLF, i);
+ tbuf_printf(out, " usage: %zu" CRLF, namespace[i].usage);
+ }
}
void
diff --git a/mod/box/box_cfg.cfg_tmpl b/mod/box/box_cfg.cfg_tmpl
index d6cd2b3..dd6dd1c 100644
--- a/mod/box/box_cfg.cfg_tmpl
+++ b/mod/box/box_cfg.cfg_tmpl
@@ -63,9 +63,11 @@ wal_feeder_port=0, ro
namespace = [
{
- enabled = -1, required
- cardinality = -1
- estimated_rows = 0
+ enabled = -1, ro, required
+ cardinality = -1, ro
+ estimated_rows = 0, ro
+ # Namespace limit in MBytes (0 stands for unlimited)
+ limit = 0.0
index = [
{
type = "", required
@@ -77,6 +79,6 @@ namespace = [
}, ro, required
], required
}, ro, required
- ], required
- }, ro
+ ], ro, required
+ }
], ro, required
diff --git a/mod/box/index.m b/mod/box/index.m
index 31070b8..e6a2fd1 100644
--- a/mod/box/index.m
+++ b/mod/box/index.m
@@ -306,6 +306,7 @@ index_remove_hash_num(struct index *self, struct box_tuple
*tuple)
tnt_raise(tnt_BoxException,
reason:"key is not u32"
errcode:ERR_CODE_ILLEGAL_PARAMS);
assoc_delete(int_ptr_map, self->idx.int_hash, num);
+ tnt_namespace_update_usage(self->namespace, -(sizeof(num) +
sizeof(tuple)));
#ifdef DEBUG
say_debug("index_remove_hash_num(self:%p, key:%i)", self, num);
#endif
@@ -322,6 +323,7 @@ index_remove_hash_num64(struct index *self, struct
box_tuple *tuple)
tnt_raise(tnt_BoxException,
reason:"key is not u64"
errcode:ERR_CODE_ILLEGAL_PARAMS);
assoc_delete(int64_ptr_map, self->idx.int64_hash, num);
+ tnt_namespace_update_usage(self->namespace, -(sizeof(num) +
sizeof(tuple)));
#ifdef DEBUG
say_debug("index_remove_hash_num(self:%p, key:%"PRIu64")", self, num);
#endif
@@ -332,6 +334,7 @@ index_remove_hash_str(struct index *self, struct box_tuple
*tuple)
{
void *key = tuple_field(tuple, self->key_field->fieldno);
assoc_delete(lstr_ptr_map, self->idx.str_hash, key);
+ tnt_namespace_update_usage(self->namespace, -(sizeof(key) +
sizeof(tuple)));
#ifdef DEBUG
u32 size = load_varint32(&key);
say_debug("index_remove_hash_str(self:%p, key:'%.*s')", self, size, (u8
*)key);
@@ -343,6 +346,7 @@ index_remove_tree_str(struct index *self, struct box_tuple
*tuple)
{
struct tree_index_member *member = tuple2tree_index_member(self, tuple,
NULL);
sptree_str_t_delete(self->idx.tree, member);
+ tnt_namespace_update_usage(self->namespace,
-SIZEOF_TREE_INDEX_MEMBER(self));
}
static void
@@ -352,6 +356,9 @@ index_replace_hash_num(struct index *self, struct box_tuple
*old_tuple, struct b
u32 key_size = load_varint32(&key);
u32 num = *(u32 *)key;
+ /* see index_replace_tree_str for comments */
+ tnt_namespace_update_usage(self->namespace, sizeof(num) +
sizeof(tuple));
+
if (key_size != 4)
tnt_raise(tnt_BoxException,
reason:"key is not u32"
errcode:ERR_CODE_ILLEGAL_PARAMS);
@@ -377,6 +384,9 @@ index_replace_hash_num64(struct index *self, struct
box_tuple *old_tuple, struct
u32 key_size = load_varint32(&key);
u64 num = *(u64 *)key;
+ /* see index_replace_tree_str for comments */
+ tnt_namespace_update_usage(self->namespace, sizeof(num) +
sizeof(tuple));
+
if (key_size != 8)
tnt_raise(tnt_BoxException,
reason:"key is not u64"
errcode:ERR_CODE_ILLEGAL_PARAMS);
@@ -400,6 +410,9 @@ index_replace_hash_str(struct index *self, struct box_tuple
*old_tuple, struct b
{
void *key = tuple_field(tuple, self->key_field->fieldno);
+ /* see index_replace_tree_str for comments */
+ tnt_namespace_update_usage(self->namespace, sizeof(key) +
sizeof(tuple));
+
if (key == NULL)
tnt_raise(tnt_BoxException,
reason:"Supplied tuple misses a field which is part
of an index"
@@ -421,6 +434,13 @@ index_replace_hash_str(struct index *self, struct
box_tuple *old_tuple, struct b
static void
index_replace_tree_str(struct index *self, struct box_tuple *old_tuple, struct
box_tuple *tuple)
{
+ /*
+ * Update usage at the beggining because if any error have been
+ * occured there is no way to determine whether update of index was
+ * successfull. So we always decrease usage during index cleanup.
+ */
+ tnt_namespace_update_usage(self->namespace,
SIZEOF_TREE_INDEX_MEMBER(self));
+
if (tuple->cardinality < self->field_cmp_order_cnt)
tnt_raise(tnt_BoxException,
reason:"Supplied tuple misses a field which is part
of an index"
diff --git a/test/box/show.result b/test/box/show.result
index 53f2d43..8860e40 100644
--- a/test/box/show.result
+++ b/test/box/show.result
@@ -64,6 +64,7 @@ configuration:
namespace[0].enabled: "1"
namespace[0].cardinality: "-1"
namespace[0].estimated_rows: "0"
+ namespace[0].limit: "0"
namespace[0].index[0].type: "HASH"
namespace[0].index[0].unique: "1"
namespace[0].index[0].key_field[0].fieldno: "0"
@@ -105,4 +106,7 @@ info:
recovery_lag: 0.000
recovery_last_update: 0.000
status: primary
+ namespace_stat:
+ namespace_0:
+ usage: 0
...
diff --git a/test/box_big/limit.result b/test/box_big/limit.result
new file mode 100644
index 0000000..cce04ab
--- /dev/null
+++ b/test/box_big/limit.result
@@ -0,0 +1,95 @@
+
+#
+# Test cases for:
https://blueprints.launchpad.net/tarantool/+spec/namespace-limits
+# Limit the total amount of memory consumed by a namespace
+#
+
+
+#
+# check namespace limit
+# insert several tuples
+#
+
+insert into t0 values (0, 'tuple')
+Insert OK, 1 row affected
+insert into t0 values (1, 'tuple')
+Insert OK, 1 row affected
+insert into t0 values (2, 'tuple')
+Insert OK, 1 row affected
+insert into t0 values (3, 'tuple')
+Insert OK, 1 row affected
+insert into t0 values (4, 'tuple')
+Insert OK, 1 row affected
+insert into t0 values (5, 'tuple')
+Insert OK, 1 row affected
+insert into t0 values (6, 'tuple')
+Insert OK, 1 row affected
+insert into t0 values (7, 'tuple')
+Insert OK, 1 row affected
+insert into t0 values (8, 'tuple')
+An error occurred: ERR_CODE_NAMESPACE_LIMIT, 'Namespace limit has been
exceeded'
+insert into t0 values (9, 'tuple')
+An error occurred: ERR_CODE_NAMESPACE_LIMIT, 'Namespace limit has been
exceeded'
+usage = 376
+
+#
+# free some space in namespace
+#
+
+delete from t0 where k0 = 0
+Delete OK, 1 row affected
+delete from t0 where k0 = 1
+Delete OK, 1 row affected
+delete from t0 where k0 = 2
+Delete OK, 1 row affected
+usage = 235
+insert into t0 values (8, 'tuple')
+Insert OK, 1 row affected
+insert into t0 values (9, 'tuple')
+Insert OK, 1 row affected
+usage = 329
+
+#
+# try to decrease namespace limit in runtime
+#
+
+reload configuration
+---
+fail:
+ - Could not change namespace[0] limit: it's lower than current namespace usage
+...
+
+#
+# try to increase namespace limit in runtime
+#
+
+reload configuration
+---
+ok
+...
+
+#
+# check that limit is changed: insert a lot of tuples
+#
+
+insert into t0 values (10, 'tuple')
+Insert OK, 1 row affected
+insert into t0 values (11, 'tuple')
+Insert OK, 1 row affected
+insert into t0 values (12, 'tuple')
+Insert OK, 1 row affected
+insert into t0 values (13, 'tuple')
+Insert OK, 1 row affected
+insert into t0 values (14, 'tuple')
+Insert OK, 1 row affected
+insert into t0 values (15, 'tuple')
+Insert OK, 1 row affected
+insert into t0 values (16, 'tuple')
+Insert OK, 1 row affected
+insert into t0 values (17, 'tuple')
+Insert OK, 1 row affected
+insert into t0 values (18, 'tuple')
+Insert OK, 1 row affected
+insert into t0 values (19, 'tuple')
+Insert OK, 1 row affected
+usage = 799
diff --git a/test/box_big/limit.test b/test/box_big/limit.test
new file mode 100644
index 0000000..f4dd088
--- /dev/null
+++ b/test/box_big/limit.test
@@ -0,0 +1,67 @@
+# encoding: tarantool
+#
+import yaml
+def print_usage():
+ info = yaml.load(admin.execute("show info\n"))["info"]
+ print "usage = " + str(info["namespace_stat"]["namespace_0"]["usage"])
+
+print """
+#
+# Test cases for:
https://blueprints.launchpad.net/tarantool/+spec/namespace-limits
+# Limit the total amount of memory consumed by a namespace
+#
+"""
+# cleanup
+server.stop()
+server.deploy("box_big/tarantool_namespace_limit.cfg")
+
+print """
+#
+# check namespace limit
+# insert several tuples
+#
+"""
+for i in range(10):
+ exec sql "insert into t0 values ({0}, 'tuple')".format(i)
+print_usage()
+print """
+#
+# free some space in namespace
+#
+"""
+exec sql "delete from t0 where k0 = 0"
+exec sql "delete from t0 where k0 = 1"
+exec sql "delete from t0 where k0 = 2"
+print_usage()
+exec sql "insert into t0 values (8, 'tuple')"
+exec sql "insert into t0 values (9, 'tuple')"
+print_usage()
+
+print """
+#
+# try to decrease namespace limit in runtime
+#
+"""
+server.reconfigure("box_big/tarantool_namespace_limit_bad.cfg")
+
+# TODO: try to restart server with lower namespace limit
+
+print """
+#
+# try to increase namespace limit in runtime
+#
+"""
+server.reconfigure("box_big/tarantool_namespace_limit_good.cfg")
+print """
+#
+# check that limit is changed: insert a lot of tuples
+#
+"""
+for i in range(10, 20):
+ exec sql "insert into t0 values ({0}, 'tuple')".format(i)
+print_usage()
+
+# restore default server
+server.stop()
+server.deploy(self.suite_ini["config"])
+# vim: syntax=python
diff --git a/test/box_big/tarantool_namespace_limit.cfg
b/test/box_big/tarantool_namespace_limit.cfg
new file mode 100644
index 0000000..b36a521
--- /dev/null
+++ b/test/box_big/tarantool_namespace_limit.cfg
@@ -0,0 +1,26 @@
+slab_alloc_arena = 0.1
+
+pid_file = "box.pid"
+
+
+# Use -a not -a to work correctly on FreeBSD
+#
+log_level = 5
+logger="tee -a tarantool.log"
+
+primary_port = 33013
+secondary_port = 33014
+admin_port = 33015
+
+rows_per_wal = 50
+
+namespace[0].enabled = 1
+namespace[0].limit = 0.0004 # approximately 400 bytes
+namespace[0].index[0].type = "HASH"
+namespace[0].index[0].unique = 1
+namespace[0].index[0].key_field[0].fieldno = 0
+namespace[0].index[0].key_field[0].type = "STR"
+namespace[0].index[1].type = "TREE"
+namespace[0].index[1].unique = 0
+namespace[0].index[1].key_field[0].fieldno = 1
+namespace[0].index[1].key_field[0].type = "STR"
diff --git a/test/box_big/tarantool_namespace_limit_bad.cfg
b/test/box_big/tarantool_namespace_limit_bad.cfg
new file mode 100644
index 0000000..6acc880
--- /dev/null
+++ b/test/box_big/tarantool_namespace_limit_bad.cfg
@@ -0,0 +1,26 @@
+slab_alloc_arena = 0.1
+
+pid_file = "box.pid"
+
+
+# Use -a not -a to work correctly on FreeBSD
+#
+log_level = 5
+logger="tee -a tarantool.log"
+
+primary_port = 33013
+secondary_port = 33014
+admin_port = 33015
+
+rows_per_wal = 50
+
+namespace[0].enabled = 1
+namespace[0].limit = 0.0002 # approximately 200 bytes
+namespace[0].index[0].type = "HASH"
+namespace[0].index[0].unique = 1
+namespace[0].index[0].key_field[0].fieldno = 0
+namespace[0].index[0].key_field[0].type = "STR"
+namespace[0].index[1].type = "TREE"
+namespace[0].index[1].unique = 0
+namespace[0].index[1].key_field[0].fieldno = 1
+namespace[0].index[1].key_field[0].type = "STR"
diff --git a/test/box_big/tarantool_namespace_limit_good.cfg
b/test/box_big/tarantool_namespace_limit_good.cfg
new file mode 100644
index 0000000..3d0a8ff
--- /dev/null
+++ b/test/box_big/tarantool_namespace_limit_good.cfg
@@ -0,0 +1,26 @@
+slab_alloc_arena = 0.1
+
+pid_file = "box.pid"
+
+
+# Use -a not -a to work correctly on FreeBSD
+#
+log_level = 5
+logger="tee -a tarantool.log"
+
+primary_port = 33013
+secondary_port = 33014
+admin_port = 33015
+
+rows_per_wal = 50
+
+namespace[0].enabled = 1
+namespace[0].limit = 0.001 # approximately 400 bytes
+namespace[0].index[0].type = "HASH"
+namespace[0].index[0].unique = 1
+namespace[0].index[0].key_field[0].fieldno = 0
+namespace[0].index[0].key_field[0].type = "STR"
+namespace[0].index[1].type = "TREE"
+namespace[0].index[1].unique = 0
+namespace[0].index[1].key_field[0].fieldno = 1
+namespace[0].index[1].key_field[0].type = "STR"
diff --git a/test/lib/sql_ast.py b/test/lib/sql_ast.py
index 45050ad..33499f3 100644
--- a/test/lib/sql_ast.py
+++ b/test/lib/sql_ast.py
@@ -52,6 +52,7 @@ ER = {
0x00003702: ("ERR_CODE_NODE_FOUND" , "")
,
0x00003802: ("ERR_CODE_INDEX_VIOLATION" , "")
,
0x00003902: ("ERR_CODE_NO_SUCH_NAMESPACE" , "No namespace with specified
id exists") ,
+ 0x00003a02: ("ERR_CODE_NAMESPACE_LIMIT" , "Namespace limit has been
exceeded") ,
}
def format_error(return_code):
--
Tarantool -- an efficient key/value data store
_______________________________________________
Mailing list: https://launchpad.net/~tarantool-developers
Post to : [email protected]
Unsubscribe : https://launchpad.net/~tarantool-developers
More help : https://help.launchpad.net/ListHelp