diff --git a/contrib/bloom/blinsert.c b/contrib/bloom/blinsert.c index a3602178938a5476ae3f4452cceb1e50401da3f8..15ac30d55f6135dc2fa1a2a5a266a242b3deb2be 100644 --- a/contrib/bloom/blinsert.c +++ b/contrib/bloom/blinsert.c @@ -18,6 +18,7 @@ #include "miscadmin.h" #include "storage/bufmgr.h" #include "storage/indexfsm.h" +#include "storage/smgr.h" #include "utils/memutils.h" #include "utils/rel.h" @@ -159,12 +160,26 @@ blbuild(Relation heap, Relation index, IndexInfo *indexInfo) void blbuildempty(Relation index) { - if (RelationGetNumberOfBlocks(index) != 0) - elog(ERROR, "index \"%s\" already contains data", - RelationGetRelationName(index)); + Page metapage; - /* Initialize the meta page */ - BloomInitMetapage(index); + /* Construct metapage. */ + metapage = (Page) palloc(BLCKSZ); + BloomFillMetapage(index, metapage); + + /* Write the page. If archiving/streaming, XLOG it. */ + PageSetChecksumInplace(metapage, BLOOM_METAPAGE_BLKNO); + smgrwrite(index->rd_smgr, INIT_FORKNUM, BLOOM_METAPAGE_BLKNO, + (char *) metapage, true); + if (XLogIsNeeded()) + log_newpage(&index->rd_smgr->smgr_rnode.node, INIT_FORKNUM, + BLOOM_METAPAGE_BLKNO, metapage, false); + + /* + * An immediate sync is required even if we xlog'd the page, because the + * write did not go through shared_buffers and therefore a concurrent + * checkpoint may have moved the redo pointer past our xlog record. + */ + smgrimmedsync(index->rd_smgr, INIT_FORKNUM); } /* diff --git a/contrib/bloom/bloom.h b/contrib/bloom/bloom.h index cbf2eb7892766fb5bb2479ad46ec0e1ced9cadb8..c21eebfc94db87a6b7b93c698625ea30f59207bf 100644 --- a/contrib/bloom/bloom.h +++ b/contrib/bloom/bloom.h @@ -166,6 +166,7 @@ typedef BloomScanOpaqueData *BloomScanOpaque; extern void _PG_init(void); extern Datum blhandler(PG_FUNCTION_ARGS); extern void initBloomState(BloomState * state, Relation index); +extern void BloomFillMetapage(Relation index, Page metaPage); extern void BloomInitMetapage(Relation index); extern void BloomInitPage(Page page, uint16 flags); extern Buffer BloomNewBuffer(Relation index); diff --git a/contrib/bloom/blutils.c b/contrib/bloom/blutils.c index 05dbe87614326f67de30fa1f14b0aa2f1357a892..4a5b343dd0242f905571ef724b813175d29c4502 100644 --- a/contrib/bloom/blutils.c +++ b/contrib/bloom/blutils.c @@ -346,7 +346,7 @@ BloomNewBuffer(Relation index) } /* - * Initialize bloom page. + * Initialize any page of a bloom index. */ void BloomInitPage(Page page, uint16 flags) @@ -363,6 +363,8 @@ BloomInitPage(Page page, uint16 flags) /* * Adjust options of bloom index. + * + * This must produce default options when *opts is initially all-zero. */ static void adjustBloomOptions(BloomOptions *opts) @@ -378,7 +380,7 @@ adjustBloomOptions(BloomOptions *opts) errmsg("length of bloom signature (%d) is greater than maximum %d", opts->bloomLength, MAX_BLOOM_LENGTH))); - /* Check singnature length */ + /* Check signature length */ for (i = 0; i < INDEX_MAX_KEYS; i++) { /* @@ -392,46 +394,67 @@ adjustBloomOptions(BloomOptions *opts) } } +/* + * Fill in metapage for bloom index. + */ +void +BloomFillMetapage(Relation index, Page metaPage) +{ + BloomOptions *opts; + BloomMetaPageData *metadata; + + /* + * Choose the index's options. If reloptions have been assigned, use + * those, otherwise create default options by applying adjustBloomOptions + * to a zeroed chunk of memory. We apply adjustBloomOptions to existing + * reloptions too, just out of paranoia; they should be valid already. + */ + opts = (BloomOptions *) index->rd_options; + if (!opts) + opts = (BloomOptions *) palloc0(sizeof(BloomOptions)); + adjustBloomOptions(opts); + + /* + * Initialize contents of meta page, including a copy of the options, + * which are now frozen for the life of the index. + */ + BloomInitPage(metaPage, BLOOM_META); + metadata = BloomPageGetMeta(metaPage); + memset(metadata, 0, sizeof(BloomMetaPageData)); + metadata->magickNumber = BLOOM_MAGICK_NUMBER; + metadata->opts = *opts; + ((PageHeader) metaPage)->pd_lower += sizeof(BloomMetaPageData); +} + /* * Initialize metapage for bloom index. */ void BloomInitMetapage(Relation index) { - Page metaPage; Buffer metaBuffer; - BloomMetaPageData *metadata; + Page metaPage; GenericXLogState *state; /* - * Make a new buffer, since it first buffer it should be associated with + * Make a new page; since it is first page it should be associated with * block number 0 (BLOOM_METAPAGE_BLKNO). */ metaBuffer = BloomNewBuffer(index); Assert(BufferGetBlockNumber(metaBuffer) == BLOOM_METAPAGE_BLKNO); - /* Initialize bloom index options */ - if (!index->rd_options) - index->rd_options = palloc0(sizeof(BloomOptions)); - adjustBloomOptions((BloomOptions *) index->rd_options); - /* Initialize contents of meta page */ state = GenericXLogStart(index); - metaPage = GenericXLogRegisterBuffer(state, metaBuffer, GENERIC_XLOG_FULL_IMAGE); - - BloomInitPage(metaPage, BLOOM_META); - metadata = BloomPageGetMeta(metaPage); - memset(metadata, 0, sizeof(BloomMetaPageData)); - metadata->magickNumber = BLOOM_MAGICK_NUMBER; - metadata->opts = *((BloomOptions *) index->rd_options); - ((PageHeader) metaPage)->pd_lower += sizeof(BloomMetaPageData); - + metaPage = GenericXLogRegisterBuffer(state, metaBuffer, + GENERIC_XLOG_FULL_IMAGE); + BloomFillMetapage(index, metaPage); GenericXLogFinish(state); + UnlockReleaseBuffer(metaBuffer); } /* - * Initialize options for bloom index. + * Parse reloptions for bloom index, producing a BloomOptions struct. */ bytea * bloptions(Datum reloptions, bool validate) diff --git a/contrib/bloom/expected/bloom.out b/contrib/bloom/expected/bloom.out index 71700efd5ae3c8ab367f104784c24641ad5f48c6..cbc50f757b65af892094faf4082951ef5caa89d2 100644 --- a/contrib/bloom/expected/bloom.out +++ b/contrib/bloom/expected/bloom.out @@ -138,6 +138,64 @@ SELECT count(*) FROM tst WHERE i = 7 AND t = '5'; 13 (1 row) +-- Try an unlogged table too +CREATE UNLOGGED TABLE tstu ( + i int4, + t text +); +INSERT INTO tstu SELECT i%10, substr(md5(i::text), 1, 1) FROM generate_series(1,2000) i; +CREATE INDEX bloomidxu ON tstu USING bloom (i, t) WITH (col2 = 4); +SET enable_seqscan=off; +SET enable_bitmapscan=on; +SET enable_indexscan=on; +EXPLAIN (COSTS OFF) SELECT count(*) FROM tstu WHERE i = 7; + QUERY PLAN +-------------------------------------------- + Aggregate + -> Bitmap Heap Scan on tstu + Recheck Cond: (i = 7) + -> Bitmap Index Scan on bloomidxu + Index Cond: (i = 7) +(5 rows) + +EXPLAIN (COSTS OFF) SELECT count(*) FROM tstu WHERE t = '5'; + QUERY PLAN +-------------------------------------------- + Aggregate + -> Bitmap Heap Scan on tstu + Recheck Cond: (t = '5'::text) + -> Bitmap Index Scan on bloomidxu + Index Cond: (t = '5'::text) +(5 rows) + +EXPLAIN (COSTS OFF) SELECT count(*) FROM tstu WHERE i = 7 AND t = '5'; + QUERY PLAN +--------------------------------------------------------- + Aggregate + -> Bitmap Heap Scan on tstu + Recheck Cond: ((i = 7) AND (t = '5'::text)) + -> Bitmap Index Scan on bloomidxu + Index Cond: ((i = 7) AND (t = '5'::text)) +(5 rows) + +SELECT count(*) FROM tstu WHERE i = 7; + count +------- + 200 +(1 row) + +SELECT count(*) FROM tstu WHERE t = '5'; + count +------- + 112 +(1 row) + +SELECT count(*) FROM tstu WHERE i = 7 AND t = '5'; + count +------- + 13 +(1 row) + RESET enable_seqscan; RESET enable_bitmapscan; RESET enable_indexscan; diff --git a/contrib/bloom/sql/bloom.sql b/contrib/bloom/sql/bloom.sql index e9174828fe6f197e5cf3ff76a32dd79d5d67b617..22274609f201456ce4450fbf423dbeb2c7e01380 100644 --- a/contrib/bloom/sql/bloom.sql +++ b/contrib/bloom/sql/bloom.sql @@ -50,6 +50,28 @@ SELECT count(*) FROM tst WHERE i = 7; SELECT count(*) FROM tst WHERE t = '5'; SELECT count(*) FROM tst WHERE i = 7 AND t = '5'; +-- Try an unlogged table too + +CREATE UNLOGGED TABLE tstu ( + i int4, + t text +); + +INSERT INTO tstu SELECT i%10, substr(md5(i::text), 1, 1) FROM generate_series(1,2000) i; +CREATE INDEX bloomidxu ON tstu USING bloom (i, t) WITH (col2 = 4); + +SET enable_seqscan=off; +SET enable_bitmapscan=on; +SET enable_indexscan=on; + +EXPLAIN (COSTS OFF) SELECT count(*) FROM tstu WHERE i = 7; +EXPLAIN (COSTS OFF) SELECT count(*) FROM tstu WHERE t = '5'; +EXPLAIN (COSTS OFF) SELECT count(*) FROM tstu WHERE i = 7 AND t = '5'; + +SELECT count(*) FROM tstu WHERE i = 7; +SELECT count(*) FROM tstu WHERE t = '5'; +SELECT count(*) FROM tstu WHERE i = 7 AND t = '5'; + RESET enable_seqscan; RESET enable_bitmapscan; RESET enable_indexscan;