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.26 1999/07/19 07:07:18 momjian Exp $
12 *-------------------------------------------------------------------------
17 #include "access/heapam.h"
18 #include "access/hio.h"
21 * amputunique - place tuple at tid
22 * Currently on errors, calls elog. Perhaps should return -1?
23 * Possible errors include the addition of a tuple to the page
24 * between the time the linep is chosen and the page is L_UP'd.
26 * This should be coordinated with the B-tree code.
27 * Probably needs to have an amdelunique to allow for
28 * internal index records to be deleted and reordered as needed.
29 * For the heap AM, this should never be needed.
31 * Note - we assume that caller hold BUFFER_LOCK_EXCLUSIVE on the buffer.
35 RelationPutHeapTuple(Relation relation,
46 * increment access statistics
49 IncrHeapAccessStat(local_RelationPutHeapTuple);
50 IncrHeapAccessStat(global_RelationPutHeapTuple);
52 pageHeader = (Page) BufferGetPage(buffer);
53 len = (unsigned) MAXALIGN(tuple->t_len); /* be conservative */
54 Assert((int) len <= PageGetFreeSpace(pageHeader));
56 offnum = PageAddItem((Page) pageHeader, (Item) tuple->t_data,
57 tuple->t_len, InvalidOffsetNumber, LP_USED);
59 itemId = PageGetItemId((Page) pageHeader, offnum);
60 item = PageGetItem((Page) pageHeader, itemId);
62 ItemPointerSet(&((HeapTupleHeader) item)->t_ctid,
63 BufferGetBlockNumber(buffer), offnum);
66 * Let the caller do this!
68 * WriteBuffer(buffer);
71 /* return an accurate tuple */
72 ItemPointerSet(&tuple->t_self, BufferGetBlockNumber(buffer), offnum);
76 * This routine is another in the series of attempts to reduce the number
77 * of I/O's and system calls executed in the various benchmarks. In
78 * particular, this routine is used to append data to the end of a relation
79 * file without excessive lseeks. This code should do no more than 2 semops
82 * Eventually, we should cache the number of blocks in a relation somewhere.
83 * Until that time, this code will have to do an lseek to determine the number
84 * of blocks in a relation.
86 * This code should ideally do at most 4 semops, 1 lseek, and possibly 1 write
87 * to do an append; it's possible to eliminate 2 of the semops if we do direct
88 * buffer stuff (!); the lseek and the write can go if we get
89 * RelationGetNumberOfBlocks to be useful.
91 * NOTE: This code presumes that we have a write lock on the relation.
92 * Not now - we use extend locking...
94 * Also note that this routine probably shouldn't have to exist, and does
95 * screw up the call graph rather badly, but we are wasting so much time and
96 * system resources being massively general that we are losing badly in our
97 * performance benchmarks.
100 RelationPutHeapTupleAtEnd(Relation relation, HeapTuple tuple)
104 BlockNumber lastblock;
111 * Lock relation for extention. We can use LockPage here as long as in
112 * all other places we use page-level locking for indices only.
113 * Alternatevely, we could define pseudo-table as we do for
114 * transactions with XactLockTable.
116 if (!relation->rd_myxactonly)
117 LockPage(relation, 0, ExclusiveLock);
120 * XXX This does an lseek - VERY expensive - but at the moment it is
121 * the only way to accurately determine how many blocks are in a
122 * relation. A good optimization would be to get this to actually
126 lastblock = RelationGetNumberOfBlocks(relation);
130 buffer = ReadBuffer(relation, lastblock);
131 pageHeader = (Page) BufferGetPage(buffer);
134 * There was IF instead of ASSERT here ?!
136 Assert(PageIsNew((PageHeader) pageHeader));
137 buffer = ReleaseAndReadBuffer(buffer, relation, P_NEW);
138 pageHeader = (Page) BufferGetPage(buffer);
139 PageInit(pageHeader, BufferGetPageSize(buffer), 0);
142 buffer = ReadBuffer(relation, lastblock - 1);
144 LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
145 pageHeader = (Page) BufferGetPage(buffer);
146 len = (unsigned) MAXALIGN(tuple->t_len); /* be conservative */
149 * Note that this is true if the above returned a bogus page, which it
150 * will do for a completely empty relation.
153 if (len > PageGetFreeSpace(pageHeader))
155 LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
156 buffer = ReleaseAndReadBuffer(buffer, relation, P_NEW);
157 LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
158 pageHeader = (Page) BufferGetPage(buffer);
159 PageInit(pageHeader, BufferGetPageSize(buffer), 0);
161 if (len > PageGetFreeSpace(pageHeader))
162 elog(ERROR, "Tuple is too big: size %d", len);
165 if (len > MaxTupleSize)
166 elog(ERROR, "Tuple is too big: size %d, max size %d", len, MaxTupleSize);
168 if (!relation->rd_myxactonly)
169 UnlockPage(relation, 0, ExclusiveLock);
171 offnum = PageAddItem((Page) pageHeader, (Item) tuple->t_data,
172 tuple->t_len, InvalidOffsetNumber, LP_USED);
174 itemId = PageGetItemId((Page) pageHeader, offnum);
175 item = PageGetItem((Page) pageHeader, itemId);
177 lastblock = BufferGetBlockNumber(buffer);
179 ItemPointerSet(&((HeapTupleHeader) item)->t_ctid, lastblock, offnum);
181 /* return an accurate tuple */
182 ItemPointerSet(&tuple->t_self, lastblock, offnum);
184 LockBuffer(buffer, BUFFER_LOCK_UNLOCK);