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

Reply via email to