void _bitmap_create_lov_heapandindex(Relation rel, Oid lovComptypeOid, Oid *lovHeapOid, Oid *lovIndexOid, Oid lovHeapRelfilenode, Oid lovIndexRelfilenode) { char lovHeapName[NAMEDATALEN]; char lovIndexName[NAMEDATALEN]; TupleDesc tupDesc; IndexInfo *indexInfo; ObjectAddress objAddr, referenced; Oid *classObjectId; int16 *coloptions; Oid heapid; Oid idxid; int indattrs; int i; Oid unusedArrayOid = InvalidOid; Assert(rel != NULL); /* create the new names for the new lov heap and index */ snprintf(lovHeapName, sizeof(lovHeapName), "pg_bm_%u", RelationGetRelid(rel)); snprintf(lovIndexName, sizeof(lovIndexName), "pg_bm_%u_index", RelationGetRelid(rel)); heapid = get_relname_relid(lovHeapName, PG_BITMAPINDEX_NAMESPACE); /* * If heapid exists, then this is happening during re-indexing. * We allocate new relfilenodes for lov heap and lov index. * * XXX Each segment db may have different relfilenodes for lov heap and * lov index, which should not be an issue now. Ideally, we would like each * segment db use the same oids. */ if (OidIsValid(heapid)) { Relation lovHeap; Relation lovIndex; Buffer btree_metabuf; Page btree_metapage; *lovHeapOid = heapid; idxid = get_relname_relid(lovIndexName, PG_BITMAPINDEX_NAMESPACE); Assert(OidIsValid(idxid)); *lovIndexOid = idxid; lovComptypeOid = get_rel_type_id(heapid); Assert(OidIsValid(lovComptypeOid)); lovHeap = heap_open(heapid, AccessExclusiveLock); lovIndex = index_open(idxid, AccessExclusiveLock); if (OidIsValid(lovHeapRelfilenode)) setNewRelfilenodeToOid(lovHeap, lovHeapRelfilenode); else setNewRelfilenode(lovHeap); if (OidIsValid(lovIndexRelfilenode)) setNewRelfilenodeToOid(lovIndex, lovIndexRelfilenode); else setNewRelfilenode(lovIndex); /* * After creating the new relfilenode for a btee index, this is not * a btree anymore. We create the new metapage for this btree. */ btree_metabuf = _bt_getbuf(lovIndex, P_NEW, BT_WRITE); Assert (BTREE_METAPAGE == BufferGetBlockNumber(btree_metabuf)); btree_metapage = BufferGetPage(btree_metabuf); _bt_initmetapage(btree_metapage, P_NONE, 0); /* XLOG the metapage */ if (!XLog_UnconvertedCanBypassWal() && !lovIndex->rd_istemp) { // Fetch gp_persistent_relation_node information that will be added to XLOG record. RelationFetchGpRelationNodeForXLog(lovIndex); _bt_lognewpage(lovIndex, btree_metapage, BufferGetBlockNumber(btree_metabuf)); } /* This cache value is not valid anymore. */ if (lovIndex->rd_amcache) { pfree(lovIndex->rd_amcache); lovIndex->rd_amcache = NULL; } MarkBufferDirty(btree_metabuf); _bt_relbuf(lovIndex, btree_metabuf); index_close(lovIndex, NoLock); heap_close(lovHeap, NoLock); return; } /* * create a new empty heap to store all attribute values with their * corresponding block number and offset in LOV. */ tupDesc = _bitmap_create_lov_heapTupleDesc(rel); Assert(rel->rd_rel != NULL); heapid = heap_create_with_catalog(lovHeapName, PG_BITMAPINDEX_NAMESPACE, rel->rd_rel->reltablespace, *lovHeapOid, rel->rd_rel->relowner, tupDesc, /* relam */ InvalidOid, RELKIND_RELATION, RELSTORAGE_HEAP, rel->rd_rel->relisshared, false, /* bufferPoolBulkLoad */ false, 0, ONCOMMIT_NOOP, NULL /* GP Policy */, (Datum)0, true, /* valid_opts */ true, &lovComptypeOid, &unusedArrayOid, /* persistentTid */ NULL, /* persistentSerialNum */ NULL); Assert(heapid == *lovHeapOid); /* * We must bump the command counter to make the newly-created relation * tuple visible for opening. */ CommandCounterIncrement(); objAddr.classId = RelationRelationId; objAddr.objectId = *lovHeapOid; objAddr.objectSubId = 0 ; referenced.classId = RelationRelationId; referenced.objectId = RelationGetRelid(rel); referenced.objectSubId = 0; recordDependencyOn(&objAddr, &referenced, DEPENDENCY_INTERNAL); /* * create a btree index on the newly-created heap. * The key includes all attributes to be indexed in this bitmap index. */ indattrs = tupDesc->natts - 2; indexInfo = makeNode(IndexInfo); indexInfo->ii_NumIndexAttrs = indattrs; indexInfo->ii_Expressions = NIL; indexInfo->ii_ExpressionsState = NIL; indexInfo->ii_Predicate = make_ands_implicit(NULL); indexInfo->ii_PredicateState = NIL; indexInfo->ii_Unique = true; indexInfo->opaque = NULL; classObjectId = (Oid *) palloc(indattrs * sizeof(Oid)); coloptions = (int16 *) palloc(indattrs * sizeof(int16)); for (i = 0; i < indattrs; i++) { Oid typid = tupDesc->attrs[i]->atttypid; indexInfo->ii_KeyAttrNumbers[i] = i + 1; classObjectId[i] = GetDefaultOpClass(typid, BTREE_AM_OID); coloptions[i] = 0; } idxid = index_create(*lovHeapOid, lovIndexName, *lovIndexOid, indexInfo, BTREE_AM_OID, rel->rd_rel->reltablespace, classObjectId, coloptions, 0, false, false, (Oid *) NULL, true, false, false, NULL); Assert(idxid == *lovIndexOid); }
/* * emit a completed btree page, and release the working storage. */ static void _bt_blwritepage(BTWriteState *wstate, Page page, BlockNumber blkno) { // Fetch gp_persistent_relation_node information that will be added to XLOG record. RelationFetchGpRelationNodeForXLog(wstate->index); /* Ensure rd_smgr is open (could have been closed by relcache flush!) */ RelationOpenSmgr(wstate->index); /* XLOG stuff */ if (wstate->btws_use_wal) { _bt_lognewpage(wstate->index, page, blkno); } else { /* Leave the page LSN zero if not WAL-logged, but set TLI anyway */ PageSetTLI(page, ThisTimeLineID); } /* * If we have to write pages nonsequentially, fill in the space with * zeroes until we come back and overwrite. This is not logically * necessary on standard Unix filesystems (unwritten space will read as * zeroes anyway), but it should help to avoid fragmentation. The dummy * pages aren't WAL-logged though. */ while (blkno > wstate->btws_pages_written) { if (!wstate->btws_zeropage) wstate->btws_zeropage = (Page) palloc0(BLCKSZ); // -------- MirroredLock ---------- // UNDONE: Unfortunately, I think we write temp relations to the mirror... LWLockAcquire(MirroredLock, LW_SHARED); smgrextend(wstate->index->rd_smgr, wstate->btws_pages_written++, (char *) wstate->btws_zeropage, true); LWLockRelease(MirroredLock); // -------- MirroredLock ---------- } // -------- MirroredLock ---------- // UNDONE: Unfortunately, I think we write temp relations to the mirror... LWLockAcquire(MirroredLock, LW_SHARED); /* * Now write the page. We say isTemp = true even if it's not a temp * index, because there's no need for smgr to schedule an fsync for this * write; we'll do it ourselves before ending the build. */ if (blkno == wstate->btws_pages_written) { /* extending the file... */ smgrextend(wstate->index->rd_smgr, blkno, (char *) page, true); wstate->btws_pages_written++; } else { /* overwriting a block we zero-filled before */ smgrwrite(wstate->index->rd_smgr, blkno, (char *) page, true); } LWLockRelease(MirroredLock); // -------- MirroredLock ---------- pfree(page); }