/* * For each UINT key in arguments create or increment counter in * box.space.test space. */ int multi_inc(box_function_ctx_t *ctx, const char *args, const char *args_end) { static const char *SPACE_NAME = "test"; static const char *INDEX_NAME = "primary"; uint32_t space_id = box_space_id_by_name(SPACE_NAME, strlen(SPACE_NAME)); uint32_t index_id = box_index_id_by_name(space_id, INDEX_NAME, strlen(INDEX_NAME)); if (space_id == BOX_ID_NIL || index_id == BOX_ID_NIL) { return box_error_raise(ER_PROC_C, "Can't find index %s in space %s", INDEX_NAME, SPACE_NAME); } say_debug("space_id = %u, index_id = %u", space_id, index_id); uint32_t arg_count = mp_decode_array(&args); box_txn_begin(); for (uint32_t i = 0; i < arg_count; i++) { /* Decode next argument */ if (mp_typeof(*args) != MP_UINT) return box_error_raise(ER_PROC_C, "Expected uint keys"); uint32_t key = mp_decode_uint(&args); (void) key; /* Prepare MsgPack key for search */ char key_buf[16]; char *key_end = key_buf; key_end = mp_encode_array(key_end, 1); key_end = mp_encode_uint(key_end, key); assert(key_end < key_buf + sizeof(key_buf)); /* Get current value from space */ uint64_t counter = 0; box_tuple_t *tuple; if (box_index_get(space_id, index_id, key_buf, key_end, &tuple) != 0) { return -1; /* error */ } else if (tuple != NULL) { const char *field = box_tuple_field(tuple, 1); if (field == NULL || mp_typeof(*field) != MP_UINT) return box_error_raise(ER_PROC_LUA, "Invalid tuple"); counter = mp_decode_uint(&field) + 1; } /* Replace value */ char tuple_buf[16]; char *tuple_end = tuple_buf; tuple_end = mp_encode_array(tuple_end, 2); tuple_end = mp_encode_uint(tuple_end, key); /* key */ tuple_end = mp_encode_uint(tuple_end, counter); /* counter */ assert(tuple_end <= tuple_buf + sizeof(tuple_buf)); if (box_replace(space_id, tuple_buf, tuple_end, NULL) != 0) return -1; } box_txn_commit(); return 0; }
ssize_t tnt_auth(struct tnt_stream *s, const char *user, int ulen, const char *pass, int plen) { struct tnt_iheader hdr; struct iovec v[6]; int v_sz = 5; char *data = NULL, *body_start = NULL; int guest = !user || (ulen == 5 && !strncmp(user, "guest", 5)); if (guest) { user = "******"; ulen = 5; } encode_header(&hdr, TNT_OP_AUTH, s->reqid++); v[1].iov_base = (void *)hdr.header; v[1].iov_len = hdr.end - hdr.header; char body[64]; data = body; body_start = data; data = mp_encode_map(data, 2); data = mp_encode_uint(data, TNT_USERNAME); data = mp_encode_strl(data, ulen); v[2].iov_base = body_start; v[2].iov_len = data - body_start; v[3].iov_base = (void *)user; v[3].iov_len = ulen; body_start = data; data = mp_encode_uint(data, TNT_TUPLE); if (!guest) { data = mp_encode_array(data, 2); data = mp_encode_str(data, "chap-sha1", strlen("chap-sha1")); data = mp_encode_strl(data, TNT_SCRAMBLE_SIZE); char salt[64], scramble[TNT_SCRAMBLE_SIZE]; base64_decode(TNT_SNET_CAST(s)->greeting + TNT_VERSION_SIZE, TNT_SALT_SIZE, salt, 64); tnt_scramble_prepare(scramble, salt, pass, plen); v[5].iov_base = scramble; v[5].iov_len = TNT_SCRAMBLE_SIZE; v_sz++; } else { data = mp_encode_array(data, 0); } v[4].iov_base = body_start; v[4].iov_len = data - body_start; size_t package_len = 0; for (int i = 1; i < v_sz; ++i) { package_len += v[i].iov_len; } char len_prefix[9]; char *len_end = mp_encode_luint32(len_prefix, package_len); v[0].iov_base = len_prefix; v[0].iov_len = len_end - len_prefix; return s->writev(s, v, v_sz); }
int args(box_function_ctx_t *ctx, const char *args, const char *args_end) { uint32_t arg_count = mp_decode_array(&args); if (arg_count < 1) { return box_error_set(__FILE__, __LINE__, ER_PROC_C, "%s", "invalid argument count"); } if (mp_typeof(*args) != MP_UINT) { return box_error_set(__FILE__, __LINE__, ER_PROC_C, "%s", "first tuple field must be uint"); } uint32_t num = mp_decode_uint(&args); char tuple_buf[512]; char *d = tuple_buf; d = mp_encode_array(d, 2); d = mp_encode_uint(d, num); d = mp_encode_str(d, "hello", strlen("hello")); assert(d <= tuple_buf + sizeof(tuple_buf)); box_tuple_format_t *fmt = box_tuple_format_default(); box_tuple_t *tuple = box_tuple_new(fmt, tuple_buf, d); if (tuple == NULL) return -1; return box_return_tuple(ctx, tuple); }
int memcached_tuple_set(struct memcached_connection *con, const char *kpos, uint32_t klen, uint64_t expire, const char *vpos, uint32_t vlen, uint64_t cas, uint32_t flags) { (void )con; uint64_t time = fiber_time64(); uint32_t len = mp_sizeof_array(6) + mp_sizeof_str (klen) + mp_sizeof_uint (expire) + mp_sizeof_uint (time) + mp_sizeof_str (vlen) + mp_sizeof_uint (cas) + mp_sizeof_uint (flags); char *begin = (char *)box_txn_alloc(len); if (begin == NULL) { memcached_error_ENOMEM(len, "tuple"); return -1; } char *end = mp_encode_array(begin, 6); end = mp_encode_str (end, kpos, klen); end = mp_encode_uint (end, expire); end = mp_encode_uint (end, time); end = mp_encode_str (end, vpos, vlen); end = mp_encode_uint (end, cas); end = mp_encode_uint (end, flags); assert(end <= begin + len); return box_replace(con->cfg->space_id, begin, end, NULL); }
int test_reload_fail(box_function_ctx_t *ctx, const char *args, const char *args_end) { char tuple_buf[64]; char *tuple_end = tuple_buf; tuple_end = mp_encode_array(tuple_end, 1); tuple_end = mp_encode_uint(tuple_end, 2); struct tuple *tuple = box_tuple_new(box_tuple_format_default(), tuple_buf, tuple_end); return box_return_tuple(ctx, tuple); }
static int test_overflow() { plan(4); header(); const char *chk; char *d; d = data; chk = data; d = mp_encode_array(d, 1); d = mp_encode_array(d, UINT32_MAX); is(mp_check(&chk, d), 1, "mp_check array overflow") d = data; chk = data; d = mp_encode_array(d, 1); d = mp_encode_map(d, UINT32_MAX); is(mp_check(&chk, d), 1, "mp_check map overflow") d = data; chk = data; d = mp_encode_array(d, 2); d = mp_encode_str(d, "", 0); d = mp_encode_strl(d, UINT32_MAX); is(mp_check(&chk, d), 1, "mp_check str overflow") d = data; chk = data; d = mp_encode_array(d, 2); d = mp_encode_bin(d, "", 0); d = mp_encode_binl(d, UINT32_MAX); is(mp_check(&chk, d), 1, "mp_check bin overflow") footer(); return check_plan(); }
static ssize_t tnt_update_op(struct tnt_stream *ops, char op, uint32_t fieldno, const char *opdata, size_t opdata_len) { struct iovec v[2]; size_t v_sz = 2; char body[64], *data; data = body; data = mp_encode_array(data, tnt_update_op_len(op)); data = mp_encode_str(data, &op, 1); data = mp_encode_uint(data, fieldno); v[0].iov_base = body; v[0].iov_len = data - body; v[1].iov_base = (void *)opdata; v[1].iov_len = opdata_len; return ops->writev(ops, v, v_sz); }
static void test_next_on_array(uint32_t count) { note("next/check on array(%u)", count); char *d1 = data; d1 = mp_encode_array(d1, count); for (uint32_t i = 0; i < count; i++) { d1 = mp_encode_uint(d1, i % 0x7f); /* one byte */ } uint32_t len = count + mp_sizeof_array(count); const char *d2 = data; const char *d3 = data; ok(!mp_check(&d2, data + BUF_MAXLEN), "mp_check(array %u))", count); is((d1 - data), (ptrdiff_t)len, "len(array %u) == %u", count, len); is((d2 - data), (ptrdiff_t)len, "len(mp_check(array %u)) == %u", count, len); mp_next(&d3); is((d3 - data), (ptrdiff_t)len, "len(mp_next(array %u)) == %u", count, len); }
int foo(box_function_ctx_t *ctx, const char *args, const char *args_end) { static const char *SPACE_TEST_NAME = "test"; uint32_t space_test_id = box_space_id_by_name(SPACE_TEST_NAME, strlen(SPACE_TEST_NAME)); if (space_test_id == BOX_ID_NIL) { return box_error_set(__FILE__, __LINE__, ER_PROC_C, "Can't find space %s", SPACE_TEST_NAME); } char buf[16]; char *end = buf; end = mp_encode_array(end, 1); end = mp_encode_uint(end, 0); if (box_insert(space_test_id, buf, end, NULL) < 0) { return box_error_set(__FILE__, __LINE__, ER_PROC_C, "Can't insert in space %s", SPACE_TEST_NAME); } return 0; }
int memcached_tuple_get(struct memcached_connection *con, const char *key, uint32_t key_len, box_tuple_t **tuple) { /* Create key for getting previous tuple from space */ uint32_t len = mp_sizeof_array(1) + mp_sizeof_str (key_len); char *begin = (char *)box_txn_alloc(len); if (begin == NULL) { memcached_error_ENOMEM(len, "key"); return -1; } char *end = NULL; end = mp_encode_array(begin, 1); end = mp_encode_str (end, key, key_len); assert(end <= begin + len); /* Get tuple from space */ if (box_index_get(con->cfg->space_id, 0, begin, end, tuple) == -1) { return -1; } return 0; }
int test_mp_print() { plan(10); header(); char msgpack[128]; char *d = msgpack; d = mp_encode_array(d, 6); d = mp_encode_int(d, -5); d = mp_encode_uint(d, 42); d = mp_encode_str(d, "kill bill", 9); d = mp_encode_map(d, 6); d = mp_encode_str(d, "bool true", 9); d = mp_encode_bool(d, true); d = mp_encode_str(d, "bool false", 10); d = mp_encode_bool(d, false); d = mp_encode_str(d, "null", 4); d = mp_encode_nil(d); d = mp_encode_str(d, "float", 5); d = mp_encode_float(d, 3.14); d = mp_encode_str(d, "double", 6); d = mp_encode_double(d, 3.14); d = mp_encode_uint(d, 100); d = mp_encode_uint(d, 500); *d++ = 0xd4; /* let's pack smallest fixed ext */ *d++ = 0; *d++ = 0; char bin[] = "\x12test\x34\b\t\n\"bla\\-bla\"\f\r"; d = mp_encode_bin(d, bin, sizeof(bin)); assert(d <= msgpack + sizeof(msgpack)); const char *expected = "[-5, 42, \"kill bill\", " "{\"bool true\": true, \"bool false\": false, \"null\": null, " "\"float\": 3.14, \"double\": 3.14, 100: 500}, undefined, " "\"\\u0012test4\\b\\t\\n\\\"bla\\\\-bla\\\"\\f\\r\\u0000\"]"; int esize = strlen(expected); char result[256]; int fsize = mp_snprint(result, sizeof(result), msgpack); ok(fsize == esize, "mp_snprint return value"); ok(strcmp(result, expected) == 0, "mp_snprint result"); fsize = mp_snprint(NULL, 0, msgpack); ok(fsize == esize, "mp_snprint limit = 0"); fsize = mp_snprint(result, 1, msgpack); ok(fsize == esize && result[0] == '\0', "mp_snprint limit = 1"); fsize = mp_snprint(result, 2, msgpack); ok(fsize == esize && result[1] == '\0', "mp_snprint limit = 2"); fsize = mp_snprint(result, esize, msgpack); ok(fsize == esize && result[esize - 1] == '\0', "mp_snprint limit = expected"); fsize = mp_snprint(result, esize + 1, msgpack); ok(fsize == esize && result[esize] == '\0', "mp_snprint limit = expected + 1"); FILE *tmpf = tmpfile(); if (tmpf != NULL) { int fsize = mp_fprint(tmpf, msgpack); ok(fsize == esize, "mp_fprint return value"); (void) rewind(tmpf); int rsize = fread(result, 1, sizeof(result), tmpf); ok(rsize == esize && memcmp(result, expected, esize) == 0, "mp_fprint result"); fclose(tmpf); } /* stdin is read-only */ int rc = mp_fprint(stdin, msgpack); is(rc, -1, "mp_fprint I/O error"); footer(); return check_plan(); }
static int test_format(void) { plan(282); header(); const size_t buf_size = 1024; char buf[buf_size]; size_t sz; const char *fmt; const char *p, *c, *e; uint32_t len = 0; fmt = "%d %u %i %ld %lu %li %lld %llu %lli" "%hd %hu %hi %hhd %hhu %hhi"; sz = mp_format(buf, buf_size, fmt, 1, 2, 3, (long)4, (long)5, (long)6, (long long)7, (long long)8, (long long)9, (short)10, (short)11, (short)12, (char)13, (char)14, (char)15); p = buf; for (unsigned i = 0; i < 15; i++) { ok(mp_typeof(*p) == MP_UINT, "Test type on step %d", i); ok(mp_decode_uint(&p) == i + 1, "Test value on step %d", i); } sz = mp_format(buf, buf_size, fmt, -1, -2, -3, (long)-4, (long)-5, (long)-6, (long long)-7, (long long)-8, (long long)-9, (short)-10, (unsigned short)-11, (short)-12, (signed char)-13, (unsigned char)-14, (signed char)-15); p = buf; for (int i = 0; i < 15; i++) { uint64_t expects[5] = { UINT_MAX - 1, ULONG_MAX - 4, ULLONG_MAX - 7, USHRT_MAX - 10, UCHAR_MAX - 13 }; if (i % 3 == 1) { ok(mp_typeof(*p) == MP_UINT, "Test type on step %d", i); ok(mp_decode_uint(&p) == expects[i / 3], "Test value on step %d", i); } else { ok(mp_typeof(*p) == MP_INT, "Test type on step %d", i); ok(mp_decode_int(&p) == - i - 1, "Test value on step %d", i); } } char data1[32]; char *data1_end = data1; data1_end = mp_encode_array(data1_end, 2); data1_end = mp_encode_str(data1_end, "ABC", 3); data1_end = mp_encode_uint(data1_end, 11); size_t data1_len = data1_end - data1; assert(data1_len <= sizeof(data1)); char data2[32]; char *data2_end = data2; data2_end = mp_encode_int(data2_end, -1234567890); data2_end = mp_encode_str(data2_end, "DEFGHIJKLMN", 11); data2_end = mp_encode_uint(data2_end, 321); size_t data2_len = data2_end - data2; assert(data2_len <= sizeof(data2)); fmt = "%d NIL [%d %b %b] this is test" "[%d %%%% [[ %d {%s %f %% %.*s %lf %.*s NIL}" "%p %d %.*p ]] %d%d%d]"; #define TEST_PARAMS 0, 1, true, false, -1, 2, \ "flt", 0.1, 6, "double#ignored", 0.2, 0, "ignore", \ data1, 3, data2_len, data2, 4, 5, 6 sz = mp_format(buf, buf_size, fmt, TEST_PARAMS); p = buf; e = buf + sz; c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_UINT, "type"); ok(mp_decode_uint(&p) == 0, "decode"); c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_NIL, "type"); mp_decode_nil(&p); c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_ARRAY, "type"); ok(mp_decode_array(&p) == 3, "decode"); c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_UINT, "type"); ok(mp_decode_uint(&p) == 1, "decode"); c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_BOOL, "type"); ok(mp_decode_bool(&p) == true, "decode"); c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_BOOL, "type"); ok(mp_decode_bool(&p) == false, "decode"); c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_ARRAY, "type"); ok(mp_decode_array(&p) == 5, "decode"); c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_INT, "type"); ok(mp_decode_int(&p) == -1, "decode"); c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_ARRAY, "type"); ok(mp_decode_array(&p) == 1, "decode"); c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_ARRAY, "type"); ok(mp_decode_array(&p) == 5, "decode"); c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_UINT, "type"); ok(mp_decode_uint(&p) == 2, "decode"); c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_MAP, "type"); ok(mp_decode_map(&p) == 3, "decode"); c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_STR, "type"); c = mp_decode_str(&p, &len); ok(len == 3, "decode"); ok(memcmp(c, "flt", 3) == 0, "compare"); c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_FLOAT, "type"); ok(fequal(mp_decode_float(&p), 0.1), "decode"); c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_STR, "type"); c = mp_decode_str(&p, &len); ok(len == 6, "decode"); ok(memcmp(c, "double", 6) == 0, "compare"); c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_DOUBLE, "type"); ok(dequal(mp_decode_double(&p), 0.2), "decode"); c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_STR, "type"); c = mp_decode_str(&p, &len); ok(len == 0, "decode"); c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_NIL, "type"); mp_decode_nil(&p); c = p; ok(mp_check(&c, e) == 0, "check"); ok(((size_t)(c - p) == data1_len) && memcmp(p, data1, data1_len) == 0, "compare"); p = c; c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_UINT, "type"); ok(mp_decode_uint(&p) == 3, "decode"); c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_INT, "type"); ok(mp_decode_int(&p) == -1234567890, "decode"); c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_STR, "type"); c = mp_decode_str(&p, &len); ok(len == 11, "decode"); ok(memcmp(c, "DEFGHIJKLMN", 11) == 0, "compare"); c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_UINT, "type"); ok(mp_decode_uint(&p) == 321, "decode"); c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_UINT, "type"); ok(mp_decode_uint(&p) == 4, "decode"); c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_UINT, "type"); ok(mp_decode_uint(&p) == 5, "decode"); c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_UINT, "type"); ok(mp_decode_uint(&p) == 6, "decode"); ok(p == e, "nothing more"); ok(sz < 70, "no magic detected"); for (size_t lim = 0; lim <= 70; lim++) { memset(buf, 0, buf_size); size_t test_sz = mp_format(buf, lim, fmt, TEST_PARAMS); ok(test_sz == sz, "return value on step %d", (int)lim); bool all_zero = true; for(size_t z = lim; z < buf_size; z++) all_zero = all_zero && (buf[z] == 0); ok(all_zero, "buffer overflow on step %d", (int)lim); } #undef TEST_PARAMS footer(); return check_plan(); }
void _mpack_item(SV *res, SV *o) { size_t len, res_len, new_len; char *s, *res_s; res_s = SvPVbyte(res, res_len); unsigned i; if (!SvOK(o)) { new_len = res_len + mp_sizeof_nil(); res_s = SvGROW(res, new_len); SvCUR_set(res, new_len); mp_encode_nil(res_s + res_len); return; } if (SvROK(o)) { o = SvRV(o); if (SvOBJECT(o)) { SvGETMAGIC(o); HV *stash = SvSTASH(o); GV *mtd = gv_fetchmethod_autoload(stash, "msgpack", 0); if (!mtd) croak("Object has no method 'msgpack'"); dSP; ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs (sv_bless (sv_2mortal (newRV_inc(o)), stash)); PUTBACK; call_sv((SV *)GvCV(mtd), G_SCALAR); SPAGAIN; SV *pkt = POPs; if (!SvOK(pkt)) croak("O->msgpack returned undef"); s = SvPV(pkt, len); new_len = res_len + len; res_s = SvGROW(res, new_len); SvCUR_set(res, new_len); memcpy(res_s + res_len, s, len); PUTBACK; FREETMPS; LEAVE; return; } switch(SvTYPE(o)) { case SVt_PVAV: { AV *a = (AV *)o; len = av_len(a) + 1; new_len = res_len + mp_sizeof_array(len); res_s = SvGROW(res, new_len); SvCUR_set(res, new_len); mp_encode_array(res_s + res_len, len); for (i = 0; i < len; i++) { SV **item = av_fetch(a, i, 0); if (!item) _mpack_item(res, 0); else _mpack_item(res, *item); } break; } case SVt_PVHV: { HV *h = (HV *)o; len = hv_iterinit(h); new_len = res_len + mp_sizeof_map(len); res_s = SvGROW(res, new_len); SvCUR_set(res, new_len); mp_encode_map(res_s + res_len, len); for (;;) { HE * iter = hv_iternext(h); if (!iter) break; SV *k = hv_iterkeysv(iter); SV *v = HeVAL(iter); _mpack_item(res, k); _mpack_item(res, v); } break; } default: croak("Can't serialize reference"); } return; } switch(SvTYPE(o)) { case SVt_PV: case SVt_PVIV: case SVt_PVNV: case SVt_PVMG: case SVt_REGEXP: if (!looks_like_number(o)) { s = SvPV(o, len); new_len = res_len + mp_sizeof_str(len); res_s = SvGROW(res, new_len); SvCUR_set(res, new_len); mp_encode_str(res_s + res_len, s, len); break; } case SVt_NV: { NV v = SvNV(o); IV iv = (IV)v; if (v != iv) { new_len = res_len + mp_sizeof_double(v); res_s = SvGROW(res, new_len); SvCUR_set(res, new_len); mp_encode_double(res_s + res_len, v); break; } } case SVt_IV: { IV v = SvIV(o); if (v >= 0) { new_len = res_len + mp_sizeof_uint(v); res_s = SvGROW(res, new_len); SvCUR_set(res, new_len); mp_encode_uint(res_s + res_len, v); } else { new_len = res_len + mp_sizeof_int(v); res_s = SvGROW(res, new_len); SvCUR_set(res, new_len); mp_encode_int(res_s + res_len, v); } break; } default: croak("Internal msgpack error %d", SvTYPE(o)); } }
static void test_iterator_restore_after_insertion() { header(); plan(1); /* Create key_def */ uint32_t fields[] = { 0 }; uint32_t types[] = { FIELD_TYPE_UNSIGNED }; struct key_def *key_def = box_key_def_new(fields, types, 1); assert(key_def != NULL); /* Create format */ struct tuple_format *format = vy_stmt_format_new(&stmt_env, &key_def, 1, NULL, 0, 0, NULL); assert(format != NULL); tuple_format_ref(format); /* Create lsregion */ struct lsregion lsregion; struct slab_cache *slab_cache = cord_slab_cache(); lsregion_create(&lsregion, slab_cache->arena); struct vy_entry select_key = vy_entry_key_new(stmt_env.key_format, key_def, NULL, 0); struct mempool history_node_pool; mempool_create(&history_node_pool, cord_slab_cache(), sizeof(struct vy_history_node)); uint64_t restore_on_value = 20; uint64_t restore_on_value_reverse = 60; char data[16]; char *end = data; end = mp_encode_array(end, 1); end = mp_encode_uint(end, restore_on_value); struct vy_entry restore_on_key; restore_on_key.stmt = vy_stmt_new_replace(format, data, end); restore_on_key.hint = vy_stmt_hint(restore_on_key.stmt, key_def); vy_stmt_set_lsn(restore_on_key.stmt, 100); end = data; end = mp_encode_array(end, 1); end = mp_encode_uint(end, restore_on_value_reverse); struct vy_entry restore_on_key_reverse; restore_on_key_reverse.stmt = vy_stmt_new_replace(format, data, end); restore_on_key_reverse.hint = vy_stmt_hint(restore_on_key_reverse.stmt, key_def); vy_stmt_set_lsn(restore_on_key_reverse.stmt, 100); bool wrong_output = false; int i_fail = 0; for (uint64_t i = 0; i < ((1000ULL * 3) << 2); i++) { uint64_t v = i; bool direct = !(v & 1); v >>= 1; bool has40_50 = v & 1; v >>= 1; bool has40_150 = v & 1; v >>= 1; const size_t possible_count = 9; uint64_t middle_value = possible_count / 2 * 10; /* 40 */ bool hasX_100[possible_count]; /* X = 0,10,20,30,40,50,60,70,80 */ bool addX_100[possible_count]; /* X = 0,10,20,30,40,50,60,70,80 */ bool add_smth = false; for (size_t j = 0; j < possible_count; j++) { uint64_t trinity = v % 3; v /= 3; hasX_100[j] = trinity == 1; addX_100[j] = trinity == 2; add_smth = add_smth || addX_100[j]; } if (!add_smth) continue; uint64_t expected_count = 0; uint64_t expected_values[possible_count]; int64_t expected_lsns[possible_count]; if (direct) { for (size_t j = 0; j < possible_count; j++) { if (hasX_100[j]) { expected_values[expected_count] = j * 10; expected_lsns[expected_count] = 100; expected_count++; } else if (j == possible_count / 2 && has40_50) { expected_values[expected_count] = middle_value; expected_lsns[expected_count] = 50; expected_count++; } } } else { for (size_t k = possible_count; k > 0; k--) { size_t j = k - 1; if (hasX_100[j]) { expected_values[expected_count] = j * 10; expected_lsns[expected_count] = 100; expected_count++; } else if (j == possible_count / 2 && has40_50) { expected_values[expected_count] = middle_value; expected_lsns[expected_count] = 50; expected_count++; } } } /* Create mem */ struct vy_mem *mem = create_test_mem(key_def); if (has40_50) { const struct vy_stmt_template temp = STMT_TEMPLATE(50, REPLACE, 40); vy_mem_insert_template(mem, &temp); } if (has40_150) { const struct vy_stmt_template temp = STMT_TEMPLATE(150, REPLACE, 40); vy_mem_insert_template(mem, &temp); } for (size_t j = 0; j < possible_count; j++) { if (hasX_100[j]) { const struct vy_stmt_template temp = STMT_TEMPLATE(100, REPLACE, j * 10); vy_mem_insert_template(mem, &temp); } } struct vy_mem_iterator itr; struct vy_mem_iterator_stat stats = {0, {0, 0}}; struct vy_read_view rv; rv.vlsn = 100; const struct vy_read_view *prv = &rv; vy_mem_iterator_open(&itr, &stats, mem, direct ? ITER_GE : ITER_LE, select_key, &prv); struct vy_entry e; struct vy_history history; vy_history_create(&history, &history_node_pool); int rc = vy_mem_iterator_next(&itr, &history); e = vy_history_last_stmt(&history); assert(rc == 0); size_t j = 0; while (e.stmt != NULL) { if (j >= expected_count) { wrong_output = true; break; } uint32_t val = 42; tuple_field_u32(e.stmt, 0, &val); if (val != expected_values[j] || vy_stmt_lsn(e.stmt) != expected_lsns[j]) { wrong_output = true; break; } j++; if (direct && val >= middle_value) break; else if(!direct && val <= middle_value) break; int rc = vy_mem_iterator_next(&itr, &history); e = vy_history_last_stmt(&history); assert(rc == 0); } if (e.stmt == NULL && j != expected_count) wrong_output = true; if (wrong_output) { i_fail = i; break; } for (size_t j = 0; j < possible_count; j++) { if (addX_100[j]) { const struct vy_stmt_template temp = STMT_TEMPLATE(100, REPLACE, j * 10); vy_mem_insert_template(mem, &temp); } } expected_count = 0; if (direct) { for (size_t j = 0; j < possible_count; j++) { if (j * 10 <= restore_on_value) continue; if (hasX_100[j] || addX_100[j]) { expected_values[expected_count] = j * 10; expected_lsns[expected_count] = 100; expected_count++; } else if (j == possible_count / 2 && has40_50) { expected_values[expected_count] = middle_value; expected_lsns[expected_count] = 50; expected_count++; } } } else { for (size_t k = possible_count; k > 0; k--) { size_t j = k - 1; if (j * 10 >= restore_on_value_reverse) continue; if (hasX_100[j] || addX_100[j]) { expected_values[expected_count] = j * 10; expected_lsns[expected_count] = 100; expected_count++; } else if (j == possible_count / 2 && has40_50) { expected_values[expected_count] = middle_value; expected_lsns[expected_count] = 50; expected_count++; } } } if (direct) rc = vy_mem_iterator_restore(&itr, restore_on_key, &history); else rc = vy_mem_iterator_restore(&itr, restore_on_key_reverse, &history); e = vy_history_last_stmt(&history); j = 0; while (e.stmt != NULL) { if (j >= expected_count) { wrong_output = true; break; } uint32_t val = 42; tuple_field_u32(e.stmt, 0, &val); if (val != expected_values[j] || vy_stmt_lsn(e.stmt) != expected_lsns[j]) { wrong_output = true; break; } j++; int rc = vy_mem_iterator_next(&itr, &history); e = vy_history_last_stmt(&history); assert(rc == 0); } if (j != expected_count) wrong_output = true; if (wrong_output) { i_fail = i; break; } vy_history_cleanup(&history); vy_mem_delete(mem); lsregion_gc(&lsregion, 2); } ok(!wrong_output, "check wrong_output %d", i_fail); /* Clean up */ mempool_destroy(&history_node_pool); tuple_unref(select_key.stmt); tuple_unref(restore_on_key.stmt); tuple_unref(restore_on_key_reverse.stmt); tuple_format_unref(format); lsregion_destroy(&lsregion); key_def_delete(key_def); fiber_gc(); check_plan(); footer(); }