Skip to content

Commit c0777a7

Browse files
authored
Merge pull request postgrespro#86 from cybertec-postgresql/smoc_gin_options
Configurable smoc_gin_ops index resolution
2 parents 7e0a209 + b96b067 commit c0777a7

File tree

8 files changed

+138
-11
lines changed

8 files changed

+138
-11
lines changed

Makefile

+13
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ healpix_bare/healpix_bare.o : healpix_bare/healpix_bare.c
9999

100100
pg_version := $(word 2,$(shell $(PG_CONFIG) --version))
101101
has_support_functions = $(if $(filter-out 9.% 10.% 11.%,$(pg_version)),y,n)
102+
has_index_options = $(if $(filter-out 9.% 10.% 11.% 12.%,$(pg_version)),y,n)
102103

103104
crushtest: TESTS += $(CRUSH_TESTS)
104105
crushtest: installcheck
@@ -108,6 +109,13 @@ PGS_SQL += pgs_gist_support.sql
108109
TESTS += gist_support
109110
endif
110111

112+
ifneq ($(USE_HEALPIX),0)
113+
ifeq ($(has_index_options),y)
114+
PGS_SQL += pgs_moc_options.sql
115+
TESTS += moc_options
116+
endif
117+
endif
118+
111119
# "make test" uses a special initialization file that doesn't rely on "create extension"
112120
test: pg_sphere.test.sql
113121
$(pg_regress_installcheck) --temp-instance=tmp_check $(REGRESS_OPTS) init_test $(TESTS)
@@ -186,6 +194,11 @@ pg_sphere--1.3.0--1.3.1.sql:
186194
ifeq ($(has_support_functions),y)
187195
pg_sphere--1.3.1--1.3.2.sql: pgs_gist_support.sql.in
188196
endif
197+
ifneq ($(USE_HEALPIX),0)
198+
ifeq ($(has_index_options),y)
199+
pg_sphere--1.3.1--1.3.2.sql: pgs_moc_options.sql.in
200+
endif
201+
endif
189202
pg_sphere--1.3.1--1.3.2.sql: pgs_circle_sel.sql.in
190203
cat upgrade_scripts/$@.in $^ > $@
191204

doc/indices.sgm

+15-6
Original file line numberDiff line numberDiff line change
@@ -121,23 +121,32 @@
121121
The index works by casting all contained smocs to a fixed level, and
122122
for each pixel at that level, storing which smocs overlap with that
123123
pixel. This is especially beneficial for "overlaps" queries using
124-
the <literal>&amp;&amp;</literal> operator. Two levels of granularity
125-
are provided: the default opclass <literal>smoc_gin_ops</literal>
126-
works on level 5 with a resolution of 12288 pixels, while the
127-
opclass <literal>smoc_gin_ops_fine</literal> works on level 8 with
128-
786432 pixels. The downside of that approach is that storing large
124+
the <literal>&amp;&amp;</literal> operator.
125+
The downside of that approach is that storing large
129126
smocs like "all sky" (<literal>0/0-11</literal>) produces a large
130127
number of index entries.
131128
</para>
129+
<para>
130+
The default opclass <literal>smoc_gin_ops</literal> defaults to
131+
working on level 5 with a resolution of 12288 pixels (12 * 4^5).
132+
An alternative granularity can be selected by setting the
133+
<literal>order</literal> parameter on the opclass (integer value
134+
between 0 and 12; option only available on PG 13 and later).
135+
The alternative <literal>smoc_gin_ops_fine</literal> opclass works
136+
on level 8 with 786432 pixels.
137+
</para>
132138
<example>
133139
<title>Index of smoc coverage objects</title>
134140
<programlisting>
135141
<![CDATA[CREATE TABLE ivoa (]]>
136142
<![CDATA[ coverage smoc NOT NULL]]>
137143
<![CDATA[);]]>
138144
<![CDATA[-- Put in data now]]>
145+
<![CDATA[-- Create index with the defaut smoc_gin_ops opclass (order 5)]]>
139146
<![CDATA[CREATE INDEX ON ivoa USING GIN (coverage);]]>
140-
<![CDATA[-- Alternative index with more detail]]>
147+
<![CDATA[-- Alternative index with more detail on order 7]]>
148+
<![CDATA[CREATE INDEX ivoa_order_7_idx ON ivoa USING GIN (coverage smoc_gin_ops (order = 7));]]>
149+
<![CDATA[-- Alternative operator class with fixed order 8]]>
141150
<![CDATA[CREATE INDEX ivoa_fine_idx ON ivoa USING GIN (coverage smoc_gin_ops_fine);]]>
142151
</programlisting>
143152
</example>

expected/moc_options.out

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
create table moc_opt (m smoc);
2+
insert into moc_opt select format('9/%s', i)::smoc from generate_series(1, 1000) g(i);
3+
analyze moc_opt;
4+
create index moc_opt5 on moc_opt using gin (m);
5+
explain (analyze, costs off, timing off, summary off) select * from moc_opt where m && '9/1';
6+
QUERY PLAN
7+
---------------------------------------------------------------
8+
Bitmap Heap Scan on moc_opt (actual rows=1 loops=1)
9+
Recheck Cond: (m && '9/1'::smoc)
10+
Rows Removed by Index Recheck: 254
11+
Heap Blocks: exact=4
12+
-> Bitmap Index Scan on moc_opt5 (actual rows=255 loops=1)
13+
Index Cond: (m && '9/1'::smoc)
14+
(6 rows)
15+
16+
drop index moc_opt5;
17+
create index moc_opt8 on moc_opt using gin (m smoc_gin_ops_fine);
18+
explain (analyze, costs off, timing off, summary off) select * from moc_opt where m && '9/1';
19+
QUERY PLAN
20+
-------------------------------------------------------------
21+
Bitmap Heap Scan on moc_opt (actual rows=1 loops=1)
22+
Recheck Cond: (m && '9/1'::smoc)
23+
Rows Removed by Index Recheck: 2
24+
Heap Blocks: exact=1
25+
-> Bitmap Index Scan on moc_opt8 (actual rows=3 loops=1)
26+
Index Cond: (m && '9/1'::smoc)
27+
(6 rows)
28+
29+
drop index moc_opt8;
30+
create index moc_opt9 on moc_opt using gin (m smoc_gin_ops (order = 9));
31+
explain (analyze, costs off, timing off, summary off) select * from moc_opt where m && '9/1';
32+
QUERY PLAN
33+
-------------------------------------------------------------
34+
Bitmap Heap Scan on moc_opt (actual rows=1 loops=1)
35+
Recheck Cond: (m && '9/1'::smoc)
36+
Heap Blocks: exact=1
37+
-> Bitmap Index Scan on moc_opt9 (actual rows=1 loops=1)
38+
Index Cond: (m && '9/1'::smoc)
39+
(5 rows)
40+

pgs_moc_ops.sql.in

+1
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,7 @@ CREATE OPERATOR CLASS smoc_gin_ops
354354
FUNCTION 4 smoc_gin_consistent (internal, int2, smoc, int4, internal, internal, internal, internal),
355355
--FUNCTION 5 smoc_gin_compare_partial (),
356356
--FUNCTION 6 smoc_gin_tri_consistent (),
357+
--FUNCTION 7 (smoc) smoc_gin_options (internal), -- needs PG13
357358
STORAGE int4;
358359

359360
CREATE OPERATOR CLASS smoc_gin_ops_fine

pgs_moc_options.sql.in

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
-- GIN opclass options
2+
3+
CREATE FUNCTION smoc_gin_options (internal)
4+
RETURNS void
5+
AS 'MODULE_PATHNAME'
6+
LANGUAGE C
7+
PARALLEL SAFE
8+
IMMUTABLE
9+
STRICT;
10+
11+
ALTER OPERATOR FAMILY smoc_gin_ops USING gin
12+
ADD FUNCTION 7 (smoc) smoc_gin_options (internal);

sql/moc_options.sql

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
create table moc_opt (m smoc);
2+
insert into moc_opt select format('9/%s', i)::smoc from generate_series(1, 1000) g(i);
3+
analyze moc_opt;
4+
5+
create index moc_opt5 on moc_opt using gin (m);
6+
explain (analyze, costs off, timing off, summary off) select * from moc_opt where m && '9/1';
7+
drop index moc_opt5;
8+
9+
create index moc_opt8 on moc_opt using gin (m smoc_gin_ops_fine);
10+
explain (analyze, costs off, timing off, summary off) select * from moc_opt where m && '9/1';
11+
drop index moc_opt8;
12+
13+
create index moc_opt9 on moc_opt using gin (m smoc_gin_ops (order = 9));
14+
explain (analyze, costs off, timing off, summary off) select * from moc_opt where m && '9/1';

src/moc.c

+25-4
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33

44
#include <stddef.h>
55
#include <string.h>
6-
#include <access/gin.h>
6+
#include "access/gin.h"
7+
#include "access/reloptions.h"
78

89
#include "circle.h"
910
#include "polygon.h"
@@ -45,6 +46,7 @@ PG_FUNCTION_INFO_V1(smoc_gin_extract_value_fine);
4546
PG_FUNCTION_INFO_V1(smoc_gin_extract_query);
4647
PG_FUNCTION_INFO_V1(smoc_gin_extract_query_fine);
4748
PG_FUNCTION_INFO_V1(smoc_gin_consistent);
49+
PG_FUNCTION_INFO_V1(smoc_gin_options);
4850

4951
int32 smoc_output_type = 0;
5052

@@ -1079,7 +1081,6 @@ smoc_gin_extract_internal(Smoc *moc_a, int32 *nkeys, int gin_order)
10791081
if (*nkeys >= nalloc)
10801082
{
10811083
nalloc *= 2;
1082-
Assert(nalloc < 2000000);
10831084
keys = repalloc(keys, nalloc * sizeof(Datum));
10841085
}
10851086
keys[(*nkeys)++] = Int32GetDatum(p);
@@ -1094,8 +1095,9 @@ smoc_gin_extract_value(PG_FUNCTION_ARGS)
10941095
{
10951096
Smoc* moc_a = (Smoc *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
10961097
int32* nkeys = (int32 *) PG_GETARG_POINTER(1);
1098+
int order = SMOC_GIN_GET_ORDER();
10971099

1098-
PG_RETURN_DATUM(smoc_gin_extract_internal(moc_a, nkeys, MOC_GIN_ORDER));
1100+
PG_RETURN_DATUM(smoc_gin_extract_internal(moc_a, nkeys, order));
10991101
}
11001102

11011103
Datum
@@ -1114,13 +1116,14 @@ smoc_gin_extract_query(PG_FUNCTION_ARGS)
11141116
int32* nkeys = (int32 *) PG_GETARG_POINTER(1);
11151117
StrategyNumber st = PG_GETARG_UINT16(2);
11161118
int32* searchmode = (int32 *) PG_GETARG_POINTER(6);
1119+
int order = SMOC_GIN_GET_ORDER();
11171120

11181121
if (st == MOC_GIN_STRATEGY_SUBSET || (st == MOC_GIN_STRATEGY_EQUAL && moc_a->area == 0))
11191122
*searchmode = GIN_SEARCH_MODE_INCLUDE_EMPTY;
11201123
else if (st == MOC_GIN_STRATEGY_UNEQUAL)
11211124
*searchmode = GIN_SEARCH_MODE_ALL;
11221125

1123-
PG_RETURN_DATUM(smoc_gin_extract_internal(moc_a, nkeys, MOC_GIN_ORDER));
1126+
PG_RETURN_DATUM(smoc_gin_extract_internal(moc_a, nkeys, order));
11241127
}
11251128

11261129
Datum
@@ -1202,3 +1205,21 @@ smoc_gin_consistent(PG_FUNCTION_ARGS)
12021205
/* not reached */
12031206
PG_RETURN_NULL();
12041207
}
1208+
1209+
#if PG_VERSION_NUM >= 130000
1210+
Datum
1211+
smoc_gin_options(PG_FUNCTION_ARGS)
1212+
{
1213+
local_relopts *relopts = (local_relopts *) PG_GETARG_POINTER(0);
1214+
1215+
init_local_reloptions(relopts, sizeof(SMocGinOptions));
1216+
add_local_int_reloption(relopts, "order",
1217+
"smoc order to store in index",
1218+
MOC_GIN_ORDER_DEFAULT,
1219+
0,
1220+
12, /* maximum order fitting into 32bit */
1221+
offsetof(SMocGinOptions, order));
1222+
1223+
PG_RETURN_VOID();
1224+
}
1225+
#endif

src/pgs_moc.h

+18-1
Original file line numberDiff line numberDiff line change
@@ -122,12 +122,29 @@ next_interval(int32 a)
122122

123123
#define MOC_AREA_ALL_SKY 3458764513820540928
124124

125-
#define MOC_GIN_ORDER 5 /* order 5 has 12 * 4^5 = 12288 pixels */
125+
#define MOC_GIN_ORDER_DEFAULT 5 /* order 5 has 12 * 4^5 = 12288 pixels */
126126
#define MOC_GIN_ORDER_FINE 8 /* order 8 has 12 * 4^8 = 786432 pixels */
127127
#define MOC_GIN_STRATEGY_INTERSECTS 1
128128
#define MOC_GIN_STRATEGY_SUBSET 2
129129
#define MOC_GIN_STRATEGY_SUPERSET 3
130130
#define MOC_GIN_STRATEGY_EQUAL 4
131131
#define MOC_GIN_STRATEGY_UNEQUAL 5
132132

133+
/* smoc_gin_ops opclass options */
134+
#if PG_VERSION_NUM >= 130000
135+
Datum smoc_gin_options(PG_FUNCTION_ARGS);
136+
137+
typedef struct
138+
{
139+
int32 vl_len_; /* varlena header (do not touch directly!) */
140+
int order; /* smoc order to store in index (default 5) */
141+
} SMocGinOptions;
142+
143+
#define SMOC_GIN_GET_ORDER() (PG_HAS_OPCLASS_OPTIONS() ? \
144+
((SMocGinOptions *) PG_GET_OPCLASS_OPTIONS())->order : \
145+
MOC_GIN_ORDER_DEFAULT)
146+
#else
147+
#define SMOC_GIN_GET_ORDER() MOC_GIN_ORDER_DEFAULT
148+
#endif
149+
133150
#endif

0 commit comments

Comments
 (0)