heapam.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 2,410 行 · 第 1/5 页
C
2,410 行
* XXX might be better to do direct access instead of * using the generality of heapgettup(). * * XXX It is very possible that when a scan is restored, that a tuple * XXX which previously qualified may fail for time range purposes, unless * XXX some form of locking exists (ie., portals currently can act funny. * ---------------- */voidheap_restrpos(HeapScanDesc scan){ /* XXX no amrestrpos checking that ammarkpos called */ /* Note: no locking manipulations needed */ /* * unpin scan buffers */ if (BufferIsValid(scan->rs_cbuf)) ReleaseBuffer(scan->rs_cbuf); scan->rs_cbuf = InvalidBuffer; if (!ItemPointerIsValid(&scan->rs_mctid)) { scan->rs_ctup.t_datamcxt = NULL; scan->rs_ctup.t_data = NULL; } else { scan->rs_ctup.t_self = scan->rs_mctid; scan->rs_ctup.t_datamcxt = NULL; scan->rs_ctup.t_data = (HeapTupleHeader) 0x1; /* for heapgettup */ heapgettup(scan->rs_rd, 0, &(scan->rs_ctup), &(scan->rs_cbuf), scan->rs_snapshot, 0, (ScanKey) NULL); }}XLogRecPtrlog_heap_clean(Relation reln, Buffer buffer, OffsetNumber *unused, int uncnt){ xl_heap_clean xlrec; XLogRecPtr recptr; XLogRecData rdata[2]; /* Caller should not call me on a temp relation */ Assert(!reln->rd_istemp); xlrec.node = reln->rd_node; xlrec.block = BufferGetBlockNumber(buffer); rdata[0].buffer = InvalidBuffer; rdata[0].data = (char *) &xlrec; rdata[0].len = SizeOfHeapClean; rdata[0].next = &(rdata[1]); /* * The unused-offsets array is not actually in the buffer, but pretend * that it is. When XLogInsert stores the whole buffer, the offsets * array need not be stored too. */ rdata[1].buffer = buffer; if (uncnt > 0) { rdata[1].data = (char *) unused; rdata[1].len = uncnt * sizeof(OffsetNumber); } else { rdata[1].data = NULL; rdata[1].len = 0; } rdata[1].next = NULL; recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_CLEAN, rdata); return (recptr);}static XLogRecPtrlog_heap_update(Relation reln, Buffer oldbuf, ItemPointerData from, Buffer newbuf, HeapTuple newtup, bool move){ /* * Note: xlhdr is declared to have adequate size and correct alignment * for an xl_heap_header. However the two tids, if present at all, * will be packed in with no wasted space after the xl_heap_header; * they aren't necessarily aligned as implied by this struct * declaration. */ struct { xl_heap_header hdr; TransactionId tid1; TransactionId tid2; } xlhdr; int hsize = SizeOfHeapHeader; xl_heap_update xlrec; XLogRecPtr recptr; XLogRecData rdata[4]; Page page = BufferGetPage(newbuf); uint8 info = (move) ? XLOG_HEAP_MOVE : XLOG_HEAP_UPDATE; /* Caller should not call me on a temp relation */ Assert(!reln->rd_istemp); xlrec.target.node = reln->rd_node; xlrec.target.tid = from; xlrec.newtid = newtup->t_self; rdata[0].buffer = InvalidBuffer; rdata[0].data = (char *) &xlrec; rdata[0].len = SizeOfHeapUpdate; rdata[0].next = &(rdata[1]); rdata[1].buffer = oldbuf; rdata[1].data = NULL; rdata[1].len = 0; rdata[1].next = &(rdata[2]); xlhdr.hdr.t_natts = newtup->t_data->t_natts; xlhdr.hdr.t_infomask = newtup->t_data->t_infomask; xlhdr.hdr.t_hoff = newtup->t_data->t_hoff; if (move) /* remember xmax & xmin */ { TransactionId xid[2]; /* xmax, xmin */ if (newtup->t_data->t_infomask & (HEAP_XMAX_INVALID | HEAP_MARKED_FOR_UPDATE)) xid[0] = InvalidTransactionId; else xid[0] = HeapTupleHeaderGetXmax(newtup->t_data); xid[1] = HeapTupleHeaderGetXmin(newtup->t_data); memcpy((char *) &xlhdr + hsize, (char *) xid, 2 * sizeof(TransactionId)); hsize += 2 * sizeof(TransactionId); } /* * As with insert records, we need not store the rdata[2] segment if * we decide to store the whole buffer instead. */ rdata[2].buffer = newbuf; rdata[2].data = (char *) &xlhdr; rdata[2].len = hsize; rdata[2].next = &(rdata[3]); rdata[3].buffer = newbuf; /* PG73FORMAT: write bitmap [+ padding] [+ oid] + data */ rdata[3].data = (char *) newtup->t_data + offsetof(HeapTupleHeaderData, t_bits); rdata[3].len = newtup->t_len - offsetof(HeapTupleHeaderData, t_bits); rdata[3].next = NULL; /* If new tuple is the single and first tuple on page... */ if (ItemPointerGetOffsetNumber(&(newtup->t_self)) == FirstOffsetNumber && PageGetMaxOffsetNumber(page) == FirstOffsetNumber) { info |= XLOG_HEAP_INIT_PAGE; rdata[2].buffer = rdata[3].buffer = InvalidBuffer; } recptr = XLogInsert(RM_HEAP_ID, info, rdata); return (recptr);}XLogRecPtrlog_heap_move(Relation reln, Buffer oldbuf, ItemPointerData from, Buffer newbuf, HeapTuple newtup){ return (log_heap_update(reln, oldbuf, from, newbuf, newtup, true));}static voidheap_xlog_clean(bool redo, XLogRecPtr lsn, XLogRecord *record){ xl_heap_clean *xlrec = (xl_heap_clean *) XLogRecGetData(record); Relation reln; Buffer buffer; Page page; if (!redo || (record->xl_info & XLR_BKP_BLOCK_1)) return; reln = XLogOpenRelation(redo, RM_HEAP_ID, xlrec->node); if (!RelationIsValid(reln)) return; buffer = XLogReadBuffer(false, reln, xlrec->block); if (!BufferIsValid(buffer)) elog(PANIC, "heap_clean_redo: no block"); page = (Page) BufferGetPage(buffer); if (PageIsNew((PageHeader) page)) elog(PANIC, "heap_clean_redo: uninitialized page"); if (XLByteLE(lsn, PageGetLSN(page))) { UnlockAndReleaseBuffer(buffer); return; } if (record->xl_len > SizeOfHeapClean) { OffsetNumber *unused; OffsetNumber *unend; ItemId lp; unused = (OffsetNumber *) ((char *) xlrec + SizeOfHeapClean); unend = (OffsetNumber *) ((char *) xlrec + record->xl_len); while (unused < unend) { lp = PageGetItemId(page, *unused + 1); lp->lp_flags &= ~LP_USED; unused++; } } PageRepairFragmentation(page, NULL); PageSetLSN(page, lsn); PageSetSUI(page, ThisStartUpID); /* prev sui */ UnlockAndWriteBuffer(buffer);}static voidheap_xlog_delete(bool redo, XLogRecPtr lsn, XLogRecord *record){ xl_heap_delete *xlrec = (xl_heap_delete *) XLogRecGetData(record); Relation reln; Buffer buffer; Page page; OffsetNumber offnum; ItemId lp = NULL; HeapTupleHeader htup; if (redo && (record->xl_info & XLR_BKP_BLOCK_1)) return; reln = XLogOpenRelation(redo, RM_HEAP_ID, xlrec->target.node); if (!RelationIsValid(reln)) return; buffer = XLogReadBuffer(false, reln, ItemPointerGetBlockNumber(&(xlrec->target.tid))); if (!BufferIsValid(buffer)) elog(PANIC, "heap_delete_%sdo: no block", (redo) ? "re" : "un"); page = (Page) BufferGetPage(buffer); if (PageIsNew((PageHeader) page)) elog(PANIC, "heap_delete_%sdo: uninitialized page", (redo) ? "re" : "un"); if (redo) { if (XLByteLE(lsn, PageGetLSN(page))) /* changes are applied */ { UnlockAndReleaseBuffer(buffer); return; } } else if (XLByteLT(PageGetLSN(page), lsn)) /* changes are not applied * ?! */ elog(PANIC, "heap_delete_undo: bad page LSN"); offnum = ItemPointerGetOffsetNumber(&(xlrec->target.tid)); if (PageGetMaxOffsetNumber(page) >= offnum) lp = PageGetItemId(page, offnum); if (PageGetMaxOffsetNumber(page) < offnum || !ItemIdIsUsed(lp)) elog(PANIC, "heap_delete_%sdo: invalid lp", (redo) ? "re" : "un"); htup = (HeapTupleHeader) PageGetItem(page, lp); if (redo) { htup->t_infomask &= ~(HEAP_XMAX_COMMITTED | HEAP_XMAX_INVALID | HEAP_MARKED_FOR_UPDATE | HEAP_MOVED); HeapTupleHeaderSetXmax(htup, record->xl_xid); HeapTupleHeaderSetCmax(htup, FirstCommandId); /* Make sure there is no forward chain link in t_ctid */ htup->t_ctid = xlrec->target.tid; PageSetLSN(page, lsn); PageSetSUI(page, ThisStartUpID); UnlockAndWriteBuffer(buffer); return; } elog(PANIC, "heap_delete_undo: unimplemented");}static voidheap_xlog_insert(bool redo, XLogRecPtr lsn, XLogRecord *record){ xl_heap_insert *xlrec = (xl_heap_insert *) XLogRecGetData(record); Relation reln; Buffer buffer; Page page; OffsetNumber offnum; if (redo && (record->xl_info & XLR_BKP_BLOCK_1)) return; reln = XLogOpenRelation(redo, RM_HEAP_ID, xlrec->target.node); if (!RelationIsValid(reln)) return; buffer = XLogReadBuffer((redo) ? true : false, reln, ItemPointerGetBlockNumber(&(xlrec->target.tid))); if (!BufferIsValid(buffer)) return; page = (Page) BufferGetPage(buffer); if (PageIsNew((PageHeader) page) && (!redo || !(record->xl_info & XLOG_HEAP_INIT_PAGE))) elog(PANIC, "heap_insert_%sdo: uninitialized page", (redo) ? "re" : "un"); if (redo) { struct { HeapTupleHeaderData hdr; char data[MaxTupleSize]; } tbuf; HeapTupleHeader htup; xl_heap_header xlhdr; uint32 newlen; if (record->xl_info & XLOG_HEAP_INIT_PAGE) PageInit(page, BufferGetPageSize(buffer), 0); if (XLByteLE(lsn, PageGetLSN(page))) /* changes are applied */ { UnlockAndReleaseBuffer(buffer); return; } offnum = ItemPointerGetOffsetNumber(&(xlrec->target.tid)); if (PageGetMaxOffsetNumber(page) + 1 < offnum) elog(PANIC, "heap_insert_redo: invalid max offset number"); newlen = record->xl_len - SizeOfHeapInsert - SizeOfHeapHeader; Assert(newlen <= MaxTupleSize); memcpy((char *) &xlhdr, (char *) xlrec + SizeOfHeapInsert, SizeOfHeapHeader); htup = &tbuf.hdr; MemSet((char *) htup, 0, sizeof(HeapTupleHeaderData)); /* PG73FORMAT: get bitmap [+ padding] [+ oid] + data */ memcpy((char *) htup + offsetof(HeapTupleHeaderData, t_bits), (char *) xlrec + SizeOfHeapInsert + SizeOfHeapHeader, newlen); newlen += offsetof(HeapTupleHeaderData, t_bits); htup->t_natts = xlhdr.t_natts; htup->t_infomask = xlhdr.t_infomask; htup->t_hoff = xlhdr.t_hoff; HeapTupleHeaderSetXmin(htup, record->xl_xid); HeapTupleHeaderSetCmin(htup, FirstCommandId); htup->t_ctid = xlrec->target.tid; offnum = PageAddItem(page, (Item) htup, newlen, offnum, LP_USED | OverwritePageMode); if (offnum == InvalidOffsetNumber) elog(PANIC, "heap_insert_redo: failed to add tuple"); PageSetLSN(page, lsn); PageSetSUI(page, ThisStartUpID); /* prev sui */ UnlockAndWriteBuffer(buffer); return; } /* undo insert */ if (XLByteLT(PageGetLSN(page), lsn)) /* changes are not applied * ?! */ elog(PANIC, "heap_insert_undo: bad page LSN"); elog(PANIC, "heap_insert_undo: unimplemented");}/* * Handles UPDATE & MOVE */static voidheap_xlog_update(bool redo, XLogRecPtr lsn, XLogRecord *record, bool move){ xl_heap_update *xlrec = (xl_heap_update *) XLogRecGetData(record); Relation reln = XLogOpenRelation(redo, RM_HEAP_ID, xlrec->target.node); Buffer buffer; bool samepage = (ItemPointerGetBlockNumber(&(xlrec->newtid)) == ItemPointerGetBlockNumber(&(xlrec->target.tid))); Page page; OffsetNumber offnum; ItemId lp = NULL; HeapTupleHeader htup; if (!RelationIsValid(reln)) return; if (redo && (record->xl_info & XLR_BKP_BLOCK_1)) goto newt; /* Deal with old tuple version */ buffer = XLogReadBuffer(false, reln, ItemPointerGetBlockNumber(&(xlrec->target.tid))); if (!BufferIsValid(buffer)) elog(PANIC, "heap_update_%sdo: no block", (redo) ? "re" : "un"); page = (Page) BufferGetPage(buffer); if (PageIsNew((PageHeader) page)) elog(PANIC, "heap_update_%sdo: uninitialized old page", (redo) ? "re" : "un"); if (redo) { if (XLByteLE(lsn, PageGetLSN(page))) /* changes are applied */ { UnlockAndReleaseBuffer(buffer); if (samepage) return; goto newt; } } else if (XLByteLT(PageGetLSN(page), lsn)) /* changes are not applied * ?! */ elog(PANIC, "heap_update_undo: bad old tuple page LSN"); offnum = ItemPointerGetOffsetNumber(&(xlrec->target.tid)); if (PageGetMaxOffsetNumber(page) >= offnum) lp = PageGetItemId(page, offnum); if (PageGetMaxOffsetNumber(page) < offnum || !ItemIdIsUsed(lp)) elog(PANIC, "heap_update_%sdo: invalid lp", (redo) ? "re" : "un"); htup = (HeapTupleHeader) PageGetItem(page, lp); if (redo) { if (move) { htup->t_infomask &= ~(HEAP_XMIN_COMMITTED | HEAP_XMIN_INVALID | HEAP_MOVED_IN); htup->t_infomask |= HEAP_MOVED_OFF; HeapTupleHeaderSetXvac(htup, record->xl_xid); /* Make sure there is no forward chain link in t_ctid */ htup->t_ctid = xlrec->target.tid; } else { htup->t_infomask &= ~(HEAP_XMAX_COMMITTED | HEAP_XMAX_INVALID | HEAP_MARKED_FOR_UPDATE | HEAP_MOVED); HeapTupleHeaderSetXmax(htup, record->xl_xid); HeapTupleHeaderSetCmax(htup, FirstCommandId); /* Set forward chain link in t_ctid */ htup->t_ctid = xlrec->newtid; } if (samepage) goto newsame; PageSetLSN(page, lsn); PageSetSUI(page, ThisStartUpID); UnlockAndWriteBuffer(buffer); goto newt; } elog(PANIC, "heap_update_undo: unimplemented"); /* Deal with new tuple */newt:; if (redo && ((record->xl_info & XLR_BKP_BLOC
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?