[tarantool-patches] Re: [PATCH 2/2] sql: store statistics in statN as an array of integers

n.pettik korablev at tarantool.org
Tue Feb 12 02:53:59 MSK 2019


> diff --git a/src/box/sql/analyze.c b/src/box/sql/analyze.c
> index 51c63fa7a..a7aaf665d 100644
> --- a/src/box/sql/analyze.c
> +++ b/src/box/sql/analyze.c
> @@ -664,27 +664,35 @@ statGet(sqlite3_context * context, int argc, sqlite3_value ** argv)
> 		 *
> 		 *        I = (K+D-1)/D
> 		 */
> -		char *z;
> 		int i;
> 
> -		char *zRet = sqlite3MallocZero((p->nKeyCol + 1) * 25);
> +		size_t size = mp_sizeof_array(p->nKeyCol + 1);
> +		size += mp_sizeof_uint(p->nRow);
> +		for (i = 0; i < p->nKeyCol; ++i) {
> +			uint64_t nDistinct = p->current.anDLt[i] + 1;
> +			uint64_t iVal = (p->nRow + nDistinct - 1) / nDistinct;

Use Tarantool-like names: distinct_count etc

> +			size += mp_sizeof_uint(iVal);
> +		}
> +		char *zRet = sqlite3MallocZero(size);
> 		if (zRet == 0) {
> 			sqlite3_result_error_nomem(context);
> 			return;
> 		}
> -
> -		sqlite3_snprintf(24, zRet, "%llu", (u64) p->nRow);
> -		z = zRet + sqlite3Strlen30(zRet);
> -		for (i = 0; i < p->nKeyCol; i++) {
> -			u64 nDistinct = p->current.anDLt[i] + 1;
> -			u64 iVal = (p->nRow + nDistinct - 1) / nDistinct;
> -			sqlite3_snprintf(24, z, " %llu", iVal);
> -			z += sqlite3Strlen30(z);
> +		char *z = zRet;
> +		z = mp_encode_array(z, p->nKeyCol + 1);
> +		z = mp_encode_uint(z, p->nRow);
> +		for (i = 0; i < p->nKeyCol; ++i) {
> +			uint64_t nDistinct = p->current.anDLt[i] + 1;
> +			uint64_t iVal = (p->nRow + nDistinct - 1) / nDistinct;
> +			z = mp_encode_uint(z, iVal);
> 			assert(p->current.anEq[i]);
> 		}
> -		assert(z[0] == '\0' && z > zRet);
> +		const char *b = zRet;
> +		int r = mp_check(&b, z);
> +		assert(!r);

Why not assert(mp_check(&b, z) == 0); ?

> +		assert(zRet != z);
> 
> -		sqlite3_result_text(context, zRet, -1, sqlite3_free);
> +		sqlite3_result_msgpack(context, zRet, size, sqlite3_free);
> 	} else if (eCall == STAT_GET_KEY) {
> 		if (p->iGet < 0) {
> 			samplePushPrevious(p, 0);
> @@ -713,19 +721,28 @@ statGet(sqlite3_context * context, int argc, sqlite3_value ** argv)
> 		}
> 	}
> 
> -	char *zRet = sqlite3MallocZero(p->nCol * 25);
> +	int i;
> +
> +	size_t size = mp_sizeof_array(p->nCol);
> +	for (i = 0; i < p->nCol; ++i) {
> +		size += mp_sizeof_uint(aCnt[i]);
> +	}
> +
> +	char *zRet = sqlite3MallocZero(size);
> 	if (zRet == 0) {
> 		sqlite3_result_error_nomem(context);
> 	} else {
> -		int i;
> 		char *z = zRet;
> +		z = mp_encode_array(z, p->nCol);
> 		for (i = 0; i < p->nCol; i++) {
> -			sqlite3_snprintf(24, z, "%llu ", (u64) aCnt[i]);
> -			z += sqlite3Strlen30(z);
> +			z = mp_encode_uint(z, aCnt[i]);
> 		}
> -		assert(z[0] == '\0' && z > zRet);
> -		z[-1] = '\0';
> -		sqlite3_result_text(context, zRet, -1, sqlite3_free);
> +		const char *b = zRet;
> +		int r = mp_check(&b, z);
> +		assert(!r);

The same: assert(mp_check() == 0);

> +		assert(zRet != z);
> +
> +		sqlite3_result_msgpack(context, zRet, size, sqlite3_free);
> 	}
> 
> }
> @@ -1166,35 +1183,33 @@ struct analysis_index_info {
> };
> 
> /**
> - * The first argument points to a nul-terminated string
> - * containing a list of space separated integers. Load
> - * the first stat_size of these into the output arrays.
> + * The first argument points to a msg_pack array
> + * containing a list of integers. Load the first
> + * stat_size of these into the output arrays.
>  *
> - * @param stat_string String containing array of integers.
> + * @param stat_array MP_ARRAY containing array of integers.
>  * @param stat_size Size of output arrays.
>  * @param[out] stat_exact Decoded array of statistics.
>  * @param[out] stat_log Decoded array of stat logariphms.
>  */
> static void
> -decode_stat_string(const char *stat_string, int stat_size, tRowcnt *stat_exact,
> -		   LogEst *stat_log) {
> -	const char *z = stat_string;
> +decode_stat_array(const char *stat_array, int stat_size, tRowcnt *stat_exact,
> +		   LogEst *stat_log, const char **offset) {

What is the offset param? Describe it in the comment.

A bit broken indentation; put bracer at the next line.

> +	const char *z = stat_array;
> +	mp_decode_array(&z);

mp_decode_array returns number of elements in array.
It is like rude to throw away that information.

> 	if (z == NULL)
> -		z = "";
> -	for (int i = 0; *z && i < stat_size; i++) {
> -		tRowcnt v = 0;
> -		int c;
> -		while ((c = z[0]) >= '0' && c <= '9') {
> -			v = v * 10 + c - '0';
> -			z++;
> -		}
> +		return;
> +	for (int i = 0; i < stat_size; i++) {
> +		tRowcnt v = (tRowcnt) mp_decode_uint(&z);
> 		if (stat_exact != NULL)
> 			stat_exact[i] = v;
> 		if (stat_log != NULL)
> 			stat_log[i] = sqlite3LogEst(v);
> -		if (*z == ' ')
> -			z++;
> 	}
> +	if (!offset)
> +		UNUSED_PARAMETER(offset);
> +	else
> +		offset = &z;

I don’t understand why you can’t do this:

if (offset != NULL)
	offset = &z;

> @@ -1268,22 +1283,23 @@ analysis_loader(void *data, int argc, char **argv, char **unused)
> 		diag_set(OutOfMemory, stat1_size, "region", "tuple_log_est");
> 		return -1;
> 	}
> -	decode_stat_string(argv[2], column_count, stat->tuple_stat1,
> -			   stat->tuple_log_est);
> +	const char *offset;
> +	decode_stat_array(argv[2], column_count, stat->tuple_stat1,
> +			   stat->tuple_log_est, &offset);

Again indentation is broken a bit. Please, make space and tabs
visible in your code redactor.

> 	stat->is_unordered = false;
> 	stat->skip_scan_enabled = true;
> -	char *z = argv[2];
> -	/* Position ptr at the end of stat string. */
> -	for (; *z == ' ' || (*z >= '0' && *z <= '9'); ++z);
> -	while (z[0]) {
> -		if (sql_strlike_cs("unordered%", z, '[') == 0)
> +	const char *z = argv[2];
> +	uint32_t keyword_count = mp_decode_array(&z) - column_count; 

Okay, there is some mess. Lets move this part to decode_stat_array.
There you already decoded that array, know its length and so on.
Instead of using offset output parameter, simply add one bit mask or two
bool output params.

> +	while (keyword_count) {
> +		const char *sval;
> +		uint32_t sval_len;
> +		sval = mp_decode_str(&offset, &sval_len);
> +		if (!sqlite3_stricmp(sval, "unordered")) {
> 			index->def->opts.stat->is_unordered = true;
> -		else if (sql_strlike_cs("noskipscan%", z, '[') == 0)
> +		} else if (!sqlite3_stricmp(sval, "noskipscan")) {
> 			index->def->opts.stat->skip_scan_enabled = false;
> -		while (z[0] != 0 && z[0] != ' ')
> -			z++;
> -		while (z[0] == ' ')
> -			z++;
> +		}
> +		keyword_count--;
> 	}
> 	return 0;
> }

Ok, I see below some commented tests, so I guess they fail
with segfaults or assertions. Please, dig into the problem.

> -test:do_execsql_test(
> -    "analyze-6.1.3",
> -    [[
> -            SELECT "tbl", "idx", "neq", "nlt", "ndlt" FROM "_sql_stat4" where "tbl"='T1' and "idx"='I1' ORDER BY "nlt" LIMIT 1;
> -    ]], {
> -    -- <analyze-6.1.3>
> -    "T1", "I1", "221 221 221 1", "0 0 0 10", "0 0 0 10"
> -    -- </analyze-6.1.3>
> -})
> +-- test:do_execsql_test(
> +--     "analyze-6.1.3",
> +--     [[
> +--             SELECT "tbl", "idx", "neq", "nlt", "ndlt" FROM "_sql_stat4" where "tbl"='T1' and "idx"='I1' ORDER BY "nlt" LIMIT 1;
> +--     ]], {
> +--     -- <analyze-6.1.3>
> +--     "T1", "I1", "221 221 221 1", "0 0 0 10", "0 0 0 10"
> +--     -- </analyze-6.1.3>
> +-- })





More information about the Tarantool-patches mailing list