예제 #1
0
파일: function1.c 프로젝트: nunb/tarantool
/*
 * 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;
}
예제 #2
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);
}
예제 #3
0
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);
}
예제 #4
0
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);
}
예제 #5
0
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);

}
예제 #6
0
파일: msgpuck.c 프로젝트: rtsisyk/msgpuck
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();
}
예제 #7
0
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);
}
예제 #8
0
파일: msgpuck.c 프로젝트: rtsisyk/msgpuck
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);
}
예제 #9
0
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;
}
예제 #10
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;
}
예제 #11
0
파일: msgpuck.c 프로젝트: rtsisyk/msgpuck
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();
}
예제 #12
0
파일: msgpuck.c 프로젝트: rtsisyk/msgpuck
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();
}
예제 #13
0
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));
	}
}
예제 #14
0
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();
}