Here is new version of the patch. Now function pack_float is commented better. All inline keywords are removed. I haven't found any performance loss for that. Remove of static's showed 1%-7% performance loss in SELECT computation (3 test runs), so I left statics where they are.
Actually, to avoid this kind of hacks, probably, it would be better to fork GiST to GiSTv2 and implement many API changes there: 1. Bulk load API 2. Richier choose subtree API 3. Allow for key test not just NO\MAYBE answers, but SURE answer to skip key test for underlying tree And some other improvements require breaking chanes for extensions. GiST idea is almost 25, modern spatial indices vary a lot from things that were there during 90th. Best regards, Andrey Borodin, Octonica & Ural Federal University.
diff --git a/contrib/cube/cube.c b/contrib/cube/cube.c index 3feddef..9ce3cd6 100644 --- a/contrib/cube/cube.c +++ b/contrib/cube/cube.c @@ -91,14 +91,16 @@ PG_FUNCTION_INFO_V1(cube_enlarge); /* ** For internal use only */ -int32 cube_cmp_v0(NDBOX *a, NDBOX *b); -bool cube_contains_v0(NDBOX *a, NDBOX *b); -bool cube_overlap_v0(NDBOX *a, NDBOX *b); -NDBOX *cube_union_v0(NDBOX *a, NDBOX *b); -void rt_cube_size(NDBOX *a, double *sz); -NDBOX *g_cube_binary_union(NDBOX *r1, NDBOX *r2, int *sizep); -bool g_cube_leaf_consistent(NDBOX *key, NDBOX *query, StrategyNumber strategy); -bool g_cube_internal_consistent(NDBOX *key, NDBOX *query, StrategyNumber strategy); +static int32 cube_cmp_v0(NDBOX *a, NDBOX *b); +static bool cube_contains_v0(NDBOX *a, NDBOX *b); +static bool cube_overlap_v0(NDBOX *a, NDBOX *b); +static NDBOX *cube_union_v0(NDBOX *a, NDBOX *b); +static float pack_float(float actualValue, int realm); +static void rt_cube_size(NDBOX *a, double *sz); +static void rt_cube_edge(NDBOX *a, double *sz); +static NDBOX *g_cube_binary_union(NDBOX *r1, NDBOX *r2, int *sizep); +static bool g_cube_leaf_consistent(NDBOX *key, NDBOX *query, StrategyNumber strategy); +static bool g_cube_internal_consistent(NDBOX *key, NDBOX *query, StrategyNumber strategy); /* ** Auxiliary funxtions @@ -419,7 +421,27 @@ g_cube_decompress(PG_FUNCTION_ARGS) } PG_RETURN_POINTER(entry); } - +/* + * Function to pack bit flags inside float type + * Resulted value represent can be from four different "realms" + * Every value from realm 3 is greater than any value from realms 2,1 and 0. + * Every value from realm 2 is less than every value from realm 3 and greater + * than any value from realm 1 and 0, and so on. Values from the same realm + * loose two bits of precision. This technique is possible due to floating + * point numbers specification according to IEEE 754: exponent bits are highest + * (excluding sign bits, but here penalty is always positive). If float a is + * greater than float b, integer A with same bit representation as a is greater + * than integer B with same bits as b. + */ +static float +pack_float(float actualValue, int realm) +{ + /* two bits for realm, others for value */ + /* we have 4 realms */ + int realmAjustment = *((int*)&actualValue)/4; + int realCode = realm * (INT32_MAX/4) + realmAjustment; + return *((float*)&realCode); +} /* ** The GiST Penalty method for boxes @@ -428,6 +450,11 @@ g_cube_decompress(PG_FUNCTION_ARGS) Datum g_cube_penalty(PG_FUNCTION_ARGS) { + /* REALM 0: No extension is required, volume is zero, return edge */ + /* REALM 1: No extension is required, return nonzero volume */ + /* REALM 2: Volume extension is zero, return nonzero edge extension */ + /* REALM 3: Volume extension is nonzero, return it */ + GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0); GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1); float *result = (float *) PG_GETARG_POINTER(2); @@ -441,9 +468,33 @@ g_cube_penalty(PG_FUNCTION_ARGS) rt_cube_size(DatumGetNDBOX(origentry->key), &tmp2); *result = (float) (tmp1 - tmp2); - /* - * fprintf(stderr, "penalty\n"); fprintf(stderr, "\t%g\n", *result); - */ + if( *result == 0 ) + { + double tmp3 = tmp1; /* remember entry volume */ + rt_cube_edge(ud, &tmp1); + rt_cube_edge(DatumGetNDBOX(origentry->key), &tmp2); + *result = (float) (tmp1 - tmp2); + if( *result == 0 ) + { + if( tmp3 != 0 ) + { + *result = pack_float(tmp3, 1); /* REALM 1 */ + } + else + { + *result = pack_float(tmp1, 0); /* REALM 0 */ + } + } + else + { + *result = pack_float(*result, 2); /* REALM 2 */ + } + } + else + { + *result = pack_float(*result, 3); /* REALM 3 */ + } + PG_RETURN_FLOAT8(*result); } @@ -626,7 +677,7 @@ g_cube_same(PG_FUNCTION_ARGS) /* ** SUPPORT ROUTINES */ -bool +static bool g_cube_leaf_consistent(NDBOX *key, NDBOX *query, StrategyNumber strategy) @@ -658,7 +709,7 @@ g_cube_leaf_consistent(NDBOX *key, return (retval); } -bool +static bool g_cube_internal_consistent(NDBOX *key, NDBOX *query, StrategyNumber strategy) @@ -688,7 +739,7 @@ g_cube_internal_consistent(NDBOX *key, return (retval); } -NDBOX * +static NDBOX * g_cube_binary_union(NDBOX *r1, NDBOX *r2, int *sizep) { NDBOX *retval; @@ -701,7 +752,7 @@ g_cube_binary_union(NDBOX *r1, NDBOX *r2, int *sizep) /* cube_union_v0 */ -NDBOX * +static NDBOX * cube_union_v0(NDBOX *a, NDBOX *b) { int i; @@ -875,25 +926,40 @@ cube_size(PG_FUNCTION_ARGS) PG_RETURN_FLOAT8(result); } -void +static void rt_cube_size(NDBOX *a, double *size) { int i; + double result = 0; - if (a == (NDBOX *) NULL) - *size = 0.0; - else + if (a != (NDBOX *) NULL) + { + result = 1.0; + for (i = 0; i < DIM(a); i++) + result *= UR_COORD(a, i) - LL_COORD(a, i); + } + *size = Abs(result); + return; +} + +static void +rt_cube_edge(NDBOX *a, double *size) +{ + int i; + double result = 0; + + if (a != (NDBOX *) NULL) { - *size = 1.0; for (i = 0; i < DIM(a); i++) - *size = (*size) * Abs(UR_COORD(a, i) - LL_COORD(a, i)); + result += Abs(UR_COORD(a, i) - LL_COORD(a, i)); } + *size = result; return; } /* make up a metric in which one box will be 'lower' than the other -- this can be useful for sorting and to determine uniqueness */ -int32 +static int32 cube_cmp_v0(NDBOX *a, NDBOX *b) { int i; @@ -1080,7 +1146,7 @@ cube_ge(PG_FUNCTION_ARGS) /* Contains */ /* Box(A) CONTAINS Box(B) IFF pt(A) < pt(B) */ -bool +static bool cube_contains_v0(NDBOX *a, NDBOX *b) { int i; @@ -1150,7 +1216,7 @@ cube_contained(PG_FUNCTION_ARGS) /* Overlap */ /* Box(A) Overlap Box(B) IFF (pt(a)LL < pt(B)UR) && (pt(b)LL < pt(a)UR) */ -bool +static bool cube_overlap_v0(NDBOX *a, NDBOX *b) { int i;
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers