]> granicus.if.org Git - postgresql/blob - src/backend/access/heap/hio.c
pgindent run over code.
[postgresql] / src / backend / access / heap / hio.c
1 /*-------------------------------------------------------------------------
2  *
3  * hio.c
4  *        POSTGRES heap access method input/output code.
5  *
6  * Copyright (c) 1994, Regents of the University of California
7  *
8  *
9  * IDENTIFICATION
10  *        $Id: hio.c,v 1.20 1999/05/25 16:07:07 momjian Exp $
11  *
12  *-------------------------------------------------------------------------
13  */
14
15 #include <postgres.h>
16
17 #include <storage/bufpage.h>
18 #include <access/hio.h>
19 #include <access/heapam.h>
20 #include <storage/bufmgr.h>
21 #include <utils/memutils.h>
22
23 /*
24  * amputunique  - place tuple at tid
25  *       Currently on errors, calls elog.  Perhaps should return -1?
26  *       Possible errors include the addition of a tuple to the page
27  *       between the time the linep is chosen and the page is L_UP'd.
28  *
29  *       This should be coordinated with the B-tree code.
30  *       Probably needs to have an amdelunique to allow for
31  *       internal index records to be deleted and reordered as needed.
32  *       For the heap AM, this should never be needed.
33  *
34  *       Note - we assume that caller hold BUFFER_LOCK_EXCLUSIVE on the buffer.
35  *
36  */
37 void
38 RelationPutHeapTuple(Relation relation,
39                                          Buffer buffer,
40                                          HeapTuple tuple)
41 {
42         Page            pageHeader;
43         OffsetNumber offnum;
44         unsigned int len;
45         ItemId          itemId;
46         Item            item;
47
48         /* ----------------
49          *      increment access statistics
50          * ----------------
51          */
52         IncrHeapAccessStat(local_RelationPutHeapTuple);
53         IncrHeapAccessStat(global_RelationPutHeapTuple);
54
55         pageHeader = (Page) BufferGetPage(buffer);
56         len = (unsigned) DOUBLEALIGN(tuple->t_len); /* be conservative */
57         Assert((int) len <= PageGetFreeSpace(pageHeader));
58
59         offnum = PageAddItem((Page) pageHeader, (Item) tuple->t_data,
60                                                  tuple->t_len, InvalidOffsetNumber, LP_USED);
61
62         itemId = PageGetItemId((Page) pageHeader, offnum);
63         item = PageGetItem((Page) pageHeader, itemId);
64
65         ItemPointerSet(&((HeapTupleHeader) item)->t_ctid,
66                                    BufferGetBlockNumber(buffer), offnum);
67
68         /*
69          * Let the caller do this!
70          *
71          * WriteBuffer(buffer);
72          */
73
74         /* return an accurate tuple */
75         ItemPointerSet(&tuple->t_self, BufferGetBlockNumber(buffer), offnum);
76 }
77
78 /*
79  * This routine is another in the series of attempts to reduce the number
80  * of I/O's and system calls executed in the various benchmarks.  In
81  * particular, this routine is used to append data to the end of a relation
82  * file without excessive lseeks.  This code should do no more than 2 semops
83  * in the ideal case.
84  *
85  * Eventually, we should cache the number of blocks in a relation somewhere.
86  * Until that time, this code will have to do an lseek to determine the number
87  * of blocks in a relation.
88  *
89  * This code should ideally do at most 4 semops, 1 lseek, and possibly 1 write
90  * to do an append; it's possible to eliminate 2 of the semops if we do direct
91  * buffer stuff (!); the lseek and the write can go if we get
92  * RelationGetNumberOfBlocks to be useful.
93  *
94  * NOTE: This code presumes that we have a write lock on the relation.
95  * Not now - we use extend locking...
96  *
97  * Also note that this routine probably shouldn't have to exist, and does
98  * screw up the call graph rather badly, but we are wasting so much time and
99  * system resources being massively general that we are losing badly in our
100  * performance benchmarks.
101  */
102 void
103 RelationPutHeapTupleAtEnd(Relation relation, HeapTuple tuple)
104 {
105         Buffer          buffer;
106         Page            pageHeader;
107         BlockNumber lastblock;
108         OffsetNumber offnum;
109         unsigned int len;
110         ItemId          itemId;
111         Item            item;
112
113         /*
114          * Lock relation for extention. We can use LockPage here as long as in
115          * all other places we use page-level locking for indices only.
116          * Alternatevely, we could define pseudo-table as we do for
117          * transactions with XactLockTable.
118          */
119         if (!relation->rd_myxactonly)
120                 LockPage(relation, 0, ExclusiveLock);
121
122         /*
123          * XXX This does an lseek - VERY expensive - but at the moment it is
124          * the only way to accurately determine how many blocks are in a
125          * relation.  A good optimization would be to get this to actually
126          * work properly.
127          */
128
129         lastblock = RelationGetNumberOfBlocks(relation);
130
131         if (lastblock == 0)
132         {
133                 buffer = ReadBuffer(relation, lastblock);
134                 pageHeader = (Page) BufferGetPage(buffer);
135
136                 /*
137                  * There was IF instead of ASSERT here ?!
138                  */
139                 Assert(PageIsNew((PageHeader) pageHeader));
140                 buffer = ReleaseAndReadBuffer(buffer, relation, P_NEW);
141                 pageHeader = (Page) BufferGetPage(buffer);
142                 PageInit(pageHeader, BufferGetPageSize(buffer), 0);
143         }
144         else
145                 buffer = ReadBuffer(relation, lastblock - 1);
146
147         LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
148         pageHeader = (Page) BufferGetPage(buffer);
149         len = (unsigned) DOUBLEALIGN(tuple->t_len); /* be conservative */
150
151         /*
152          * Note that this is true if the above returned a bogus page, which it
153          * will do for a completely empty relation.
154          */
155
156         if (len > PageGetFreeSpace(pageHeader))
157         {
158                 LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
159                 buffer = ReleaseAndReadBuffer(buffer, relation, P_NEW);
160                 LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
161                 pageHeader = (Page) BufferGetPage(buffer);
162                 PageInit(pageHeader, BufferGetPageSize(buffer), 0);
163
164                 if (len > PageGetFreeSpace(pageHeader))
165                         elog(ERROR, "Tuple is too big: size %d", len);
166         }
167
168         if (!relation->rd_myxactonly)
169                 UnlockPage(relation, 0, ExclusiveLock);
170
171         offnum = PageAddItem((Page) pageHeader, (Item) tuple->t_data,
172                                                  tuple->t_len, InvalidOffsetNumber, LP_USED);
173
174         itemId = PageGetItemId((Page) pageHeader, offnum);
175         item = PageGetItem((Page) pageHeader, itemId);
176
177         lastblock = BufferGetBlockNumber(buffer);
178
179         ItemPointerSet(&((HeapTupleHeader) item)->t_ctid, lastblock, offnum);
180
181         /* return an accurate tuple */
182         ItemPointerSet(&tuple->t_self, lastblock, offnum);
183
184         LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
185         WriteBuffer(buffer);
186
187 }