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.2 1996/10/18 07:43:43 vadim Exp $
12 *-------------------------------------------------------------------------
18 #include "access/heapam.h"
19 #include "access/hio.h"
20 #include "access/htup.h"
22 #include "storage/block.h"
23 #include "storage/buf.h"
24 #include "storage/bufmgr.h"
25 #include "storage/bufpage.h"
26 #include "storage/itemid.h"
27 #include "storage/itemptr.h"
28 #include "storage/off.h"
30 #include "utils/memutils.h"
31 #include "utils/elog.h"
32 #include "utils/rel.h"
35 * amputunique - place tuple at tid
36 * Currently on errors, calls elog. Perhaps should return -1?
37 * Possible errors include the addition of a tuple to the page
38 * between the time the linep is chosen and the page is L_UP'd.
40 * This should be coordinated with the B-tree code.
41 * Probably needs to have an amdelunique to allow for
42 * internal index records to be deleted and reordered as needed.
43 * For the heap AM, this should never be needed.
46 RelationPutHeapTuple(Relation relation,
47 BlockNumber blockIndex,
52 BlockNumber numberOfBlocks;
59 * increment access statistics
62 IncrHeapAccessStat(local_RelationPutHeapTuple);
63 IncrHeapAccessStat(global_RelationPutHeapTuple);
65 Assert(RelationIsValid(relation));
66 Assert(HeapTupleIsValid(tuple));
68 numberOfBlocks = RelationGetNumberOfBlocks(relation);
69 Assert(blockIndex < numberOfBlocks);
71 buffer = ReadBuffer(relation, blockIndex);
72 #ifndef NO_BUFFERISVALID
73 if (!BufferIsValid(buffer)) {
74 elog(WARN, "RelationPutHeapTuple: no buffer for %ld in %s",
75 blockIndex, &relation->rd_rel->relname);
79 pageHeader = (Page)BufferGetPage(buffer);
80 len = (unsigned)DOUBLEALIGN(tuple->t_len); /* be conservative */
81 Assert((int)len <= PageGetFreeSpace(pageHeader));
83 offnum = PageAddItem((Page)pageHeader, (Item)tuple,
84 tuple->t_len, InvalidOffsetNumber, LP_USED);
86 itemId = PageGetItemId((Page)pageHeader, offnum);
87 item = PageGetItem((Page)pageHeader, itemId);
89 ItemPointerSet(&((HeapTuple)item)->t_ctid, blockIndex, offnum);
92 /* return an accurate tuple */
93 ItemPointerSet(&tuple->t_ctid, blockIndex, offnum);
97 * This routine is another in the series of attempts to reduce the number
98 * of I/O's and system calls executed in the various benchmarks. In
99 * particular, this routine is used to append data to the end of a relation
100 * file without excessive lseeks. This code should do no more than 2 semops
103 * Eventually, we should cache the number of blocks in a relation somewhere.
104 * Until that time, this code will have to do an lseek to determine the number
105 * of blocks in a relation.
107 * This code should ideally do at most 4 semops, 1 lseek, and possibly 1 write
108 * to do an append; it's possible to eliminate 2 of the semops if we do direct
109 * buffer stuff (!); the lseek and the write can go if we get
110 * RelationGetNumberOfBlocks to be useful.
112 * NOTE: This code presumes that we have a write lock on the relation.
114 * Also note that this routine probably shouldn't have to exist, and does
115 * screw up the call graph rather badly, but we are wasting so much time and
116 * system resources being massively general that we are losing badly in our
117 * performance benchmarks.
120 RelationPutHeapTupleAtEnd(Relation relation, HeapTuple tuple)
124 BlockNumber lastblock;
130 Assert(RelationIsValid(relation));
131 Assert(HeapTupleIsValid(tuple));
134 * XXX This does an lseek - VERY expensive - but at the moment it
135 * is the only way to accurately determine how many blocks are in
136 * a relation. A good optimization would be to get this to actually
140 lastblock = RelationGetNumberOfBlocks(relation);
144 buffer = ReadBuffer(relation, lastblock);
145 pageHeader = (Page)BufferGetPage(buffer);
146 if (PageIsNew((PageHeader) pageHeader))
148 buffer = ReleaseAndReadBuffer(buffer, relation, P_NEW);
149 pageHeader = (Page)BufferGetPage(buffer);
150 PageInit(pageHeader, BufferGetPageSize(buffer), 0);
154 buffer = ReadBuffer(relation, lastblock - 1);
156 pageHeader = (Page)BufferGetPage(buffer);
157 len = (unsigned)DOUBLEALIGN(tuple->t_len); /* be conservative */
160 * Note that this is true if the above returned a bogus page, which
161 * it will do for a completely empty relation.
164 if (len > PageGetFreeSpace(pageHeader))
166 buffer = ReleaseAndReadBuffer(buffer, relation, P_NEW);
167 pageHeader = (Page)BufferGetPage(buffer);
168 PageInit(pageHeader, BufferGetPageSize(buffer), 0);
170 if (len > PageGetFreeSpace(pageHeader))
171 elog(WARN, "Tuple is too big: size %d", len);
174 offnum = PageAddItem((Page)pageHeader, (Item)tuple,
175 tuple->t_len, InvalidOffsetNumber, LP_USED);
177 itemId = PageGetItemId((Page)pageHeader, offnum);
178 item = PageGetItem((Page)pageHeader, itemId);
180 lastblock = BufferGetBlockNumber(buffer);
182 ItemPointerSet(&((HeapTuple)item)->t_ctid, lastblock, offnum);
184 /* return an accurate tuple */
185 ItemPointerSet(&tuple->t_ctid, lastblock, offnum);