1 /*-------------------------------------------------------------------------
4 * POSTGRES heap access method input/output code.
6 * Copyright (c) 1994, Regents of the University of California
10 * $Id: hio.c,v 1.3 1996/10/20 06:56:02 scrappy Exp $
12 *-------------------------------------------------------------------------
16 #include "utils/rel.h"
17 #include "access/htup.h"
18 #include "storage/buf.h"
19 #include "storage/bufpage.h"
20 #include "access/relscan.h"
21 #include "access/heapam.h"
22 #include "storage/bufmgr.h"
25 * amputunique - place tuple at tid
26 * Currently on errors, calls elog. Perhaps should return -1?
27 * Possible errors include the addition of a tuple to the page
28 * between the time the linep is chosen and the page is L_UP'd.
30 * This should be coordinated with the B-tree code.
31 * Probably needs to have an amdelunique to allow for
32 * internal index records to be deleted and reordered as needed.
33 * For the heap AM, this should never be needed.
36 RelationPutHeapTuple(Relation relation,
37 BlockNumber blockIndex,
42 BlockNumber numberOfBlocks;
49 * increment access statistics
52 IncrHeapAccessStat(local_RelationPutHeapTuple);
53 IncrHeapAccessStat(global_RelationPutHeapTuple);
55 Assert(RelationIsValid(relation));
56 Assert(HeapTupleIsValid(tuple));
58 numberOfBlocks = RelationGetNumberOfBlocks(relation);
59 Assert(blockIndex < numberOfBlocks);
61 buffer = ReadBuffer(relation, blockIndex);
62 #ifndef NO_BUFFERISVALID
63 if (!BufferIsValid(buffer)) {
64 elog(WARN, "RelationPutHeapTuple: no buffer for %ld in %s",
65 blockIndex, &relation->rd_rel->relname);
69 pageHeader = (Page)BufferGetPage(buffer);
70 len = (unsigned)DOUBLEALIGN(tuple->t_len); /* be conservative */
71 Assert((int)len <= PageGetFreeSpace(pageHeader));
73 offnum = PageAddItem((Page)pageHeader, (Item)tuple,
74 tuple->t_len, InvalidOffsetNumber, LP_USED);
76 itemId = PageGetItemId((Page)pageHeader, offnum);
77 item = PageGetItem((Page)pageHeader, itemId);
79 ItemPointerSet(&((HeapTuple)item)->t_ctid, blockIndex, offnum);
82 /* return an accurate tuple */
83 ItemPointerSet(&tuple->t_ctid, blockIndex, offnum);
87 * This routine is another in the series of attempts to reduce the number
88 * of I/O's and system calls executed in the various benchmarks. In
89 * particular, this routine is used to append data to the end of a relation
90 * file without excessive lseeks. This code should do no more than 2 semops
93 * Eventually, we should cache the number of blocks in a relation somewhere.
94 * Until that time, this code will have to do an lseek to determine the number
95 * of blocks in a relation.
97 * This code should ideally do at most 4 semops, 1 lseek, and possibly 1 write
98 * to do an append; it's possible to eliminate 2 of the semops if we do direct
99 * buffer stuff (!); the lseek and the write can go if we get
100 * RelationGetNumberOfBlocks to be useful.
102 * NOTE: This code presumes that we have a write lock on the relation.
104 * Also note that this routine probably shouldn't have to exist, and does
105 * screw up the call graph rather badly, but we are wasting so much time and
106 * system resources being massively general that we are losing badly in our
107 * performance benchmarks.
110 RelationPutHeapTupleAtEnd(Relation relation, HeapTuple tuple)
114 BlockNumber lastblock;
120 Assert(RelationIsValid(relation));
121 Assert(HeapTupleIsValid(tuple));
124 * XXX This does an lseek - VERY expensive - but at the moment it
125 * is the only way to accurately determine how many blocks are in
126 * a relation. A good optimization would be to get this to actually
130 lastblock = RelationGetNumberOfBlocks(relation);
134 buffer = ReadBuffer(relation, lastblock);
135 pageHeader = (Page)BufferGetPage(buffer);
136 if (PageIsNew((PageHeader) pageHeader))
138 buffer = ReleaseAndReadBuffer(buffer, relation, P_NEW);
139 pageHeader = (Page)BufferGetPage(buffer);
140 PageInit(pageHeader, BufferGetPageSize(buffer), 0);
144 buffer = ReadBuffer(relation, lastblock - 1);
146 pageHeader = (Page)BufferGetPage(buffer);
147 len = (unsigned)DOUBLEALIGN(tuple->t_len); /* be conservative */
150 * Note that this is true if the above returned a bogus page, which
151 * it will do for a completely empty relation.
154 if (len > PageGetFreeSpace(pageHeader))
156 buffer = ReleaseAndReadBuffer(buffer, relation, P_NEW);
157 pageHeader = (Page)BufferGetPage(buffer);
158 PageInit(pageHeader, BufferGetPageSize(buffer), 0);
160 if (len > PageGetFreeSpace(pageHeader))
161 elog(WARN, "Tuple is too big: size %d", len);
164 offnum = PageAddItem((Page)pageHeader, (Item)tuple,
165 tuple->t_len, InvalidOffsetNumber, LP_USED);
167 itemId = PageGetItemId((Page)pageHeader, offnum);
168 item = PageGetItem((Page)pageHeader, itemId);
170 lastblock = BufferGetBlockNumber(buffer);
172 ItemPointerSet(&((HeapTuple)item)->t_ctid, lastblock, offnum);
174 /* return an accurate tuple */
175 ItemPointerSet(&tuple->t_ctid, lastblock, offnum);