11
11
* Portions Copyright (c) 1994, Regents of the University of California
12
12
*
13
13
* IDENTIFICATION
14
- * $PostgreSQL: pgsql/src/backend/access/gin/ginfast.c,v 1.3 2009/06/11 14:48:53 momjian Exp $
14
+ * $PostgreSQL: pgsql/src/backend/access/gin/ginfast.c,v 1.4 2009/09/15 20:31:30 tgl Exp $
15
15
*
16
16
*-------------------------------------------------------------------------
17
17
*/
@@ -41,13 +41,15 @@ typedef struct DatumArray
41
41
42
42
/*
43
43
* Build a pending-list page from the given array of tuples, and write it out.
44
+ *
45
+ * Returns amount of free space left on the page.
44
46
*/
45
47
static int32
46
48
writeListPage (Relation index , Buffer buffer ,
47
49
IndexTuple * tuples , int32 ntuples , BlockNumber rightlink )
48
50
{
49
51
Page page = BufferGetPage (buffer );
50
- int i ,
52
+ int32 i ,
51
53
freesize ,
52
54
size = 0 ;
53
55
OffsetNumber l ,
@@ -100,8 +102,6 @@ writeListPage(Relation index, Buffer buffer,
100
102
GinPageGetOpaque (page )-> maxoff = 0 ;
101
103
}
102
104
103
- freesize = PageGetFreeSpace (page );
104
-
105
105
MarkBufferDirty (buffer );
106
106
107
107
if (!index -> rd_istemp )
@@ -110,26 +110,30 @@ writeListPage(Relation index, Buffer buffer,
110
110
ginxlogInsertListPage data ;
111
111
XLogRecPtr recptr ;
112
112
113
- rdata [0 ].buffer = buffer ;
114
- rdata [0 ].buffer_std = true;
113
+ data .node = index -> rd_node ;
114
+ data .blkno = BufferGetBlockNumber (buffer );
115
+ data .rightlink = rightlink ;
116
+ data .ntuples = ntuples ;
117
+
118
+ rdata [0 ].buffer = InvalidBuffer ;
115
119
rdata [0 ].data = (char * ) & data ;
116
120
rdata [0 ].len = sizeof (ginxlogInsertListPage );
117
121
rdata [0 ].next = rdata + 1 ;
118
122
119
- rdata [1 ].buffer = InvalidBuffer ;
123
+ rdata [1 ].buffer = buffer ;
124
+ rdata [1 ].buffer_std = true;
120
125
rdata [1 ].data = workspace ;
121
126
rdata [1 ].len = size ;
122
127
rdata [1 ].next = NULL ;
123
128
124
- data .blkno = BufferGetBlockNumber (buffer );
125
- data .rightlink = rightlink ;
126
- data .ntuples = ntuples ;
127
-
128
129
recptr = XLogInsert (RM_GIN_ID , XLOG_GIN_INSERT_LISTPAGE , rdata );
129
130
PageSetLSN (page , recptr );
130
131
PageSetTLI (page , ThisTimeLineID );
131
132
}
132
133
134
+ /* get free space before releasing buffer */
135
+ freesize = PageGetExactFreeSpace (page );
136
+
133
137
UnlockReleaseBuffer (buffer );
134
138
135
139
END_CRIT_SECTION ();
@@ -165,7 +169,8 @@ makeSublist(Relation index, IndexTuple *tuples, int32 ntuples,
165
169
{
166
170
res -> nPendingPages ++ ;
167
171
writeListPage (index , prevBuffer ,
168
- tuples + startTuple , i - startTuple ,
172
+ tuples + startTuple ,
173
+ i - startTuple ,
169
174
BufferGetBlockNumber (curBuffer ));
170
175
}
171
176
else
@@ -180,7 +185,7 @@ makeSublist(Relation index, IndexTuple *tuples, int32 ntuples,
180
185
181
186
tupsize = MAXALIGN (IndexTupleSize (tuples [i ])) + sizeof (ItemIdData );
182
187
183
- if (size + tupsize >= GinListPageSize )
188
+ if (size + tupsize > GinListPageSize )
184
189
{
185
190
/* won't fit, force a new page and reprocess */
186
191
i -- ;
@@ -197,7 +202,8 @@ makeSublist(Relation index, IndexTuple *tuples, int32 ntuples,
197
202
*/
198
203
res -> tail = BufferGetBlockNumber (curBuffer );
199
204
res -> tailFreeSize = writeListPage (index , curBuffer ,
200
- tuples + startTuple , ntuples - startTuple ,
205
+ tuples + startTuple ,
206
+ ntuples - startTuple ,
201
207
InvalidBlockNumber );
202
208
res -> nPendingPages ++ ;
203
209
/* that was only one heap tuple */
@@ -237,7 +243,7 @@ ginHeapTupleFastInsert(Relation index, GinState *ginstate,
237
243
metabuffer = ReadBuffer (index , GIN_METAPAGE_BLKNO );
238
244
metapage = BufferGetPage (metabuffer );
239
245
240
- if (collector -> sumsize + collector -> ntuples * sizeof (ItemIdData ) > GIN_PAGE_FREESIZE )
246
+ if (collector -> sumsize + collector -> ntuples * sizeof (ItemIdData ) > GinListPageSize )
241
247
{
242
248
/*
243
249
* Total size is greater than one page => make sublist
@@ -265,13 +271,12 @@ ginHeapTupleFastInsert(Relation index, GinState *ginstate,
265
271
266
272
if (separateList )
267
273
{
268
- GinMetaPageData sublist ;
269
-
270
274
/*
271
275
* We should make sublist separately and append it to the tail
272
276
*/
273
- memset ( & sublist , 0 , sizeof ( GinMetaPageData )) ;
277
+ GinMetaPageData sublist ;
274
278
279
+ memset (& sublist , 0 , sizeof (GinMetaPageData ));
275
280
makeSublist (index , collector -> tuples , collector -> ntuples , & sublist );
276
281
277
282
/*
@@ -283,45 +288,44 @@ ginHeapTupleFastInsert(Relation index, GinState *ginstate,
283
288
if (metadata -> head == InvalidBlockNumber )
284
289
{
285
290
/*
286
- * Sublist becomes main list
291
+ * Main list is empty, so just copy sublist into main list
287
292
*/
288
293
START_CRIT_SECTION ();
294
+
289
295
memcpy (metadata , & sublist , sizeof (GinMetaPageData ));
290
- memcpy (& data .metadata , & sublist , sizeof (GinMetaPageData ));
291
296
}
292
297
else
293
298
{
294
299
/*
295
- * merge lists
300
+ * Merge lists
296
301
*/
297
-
298
302
data .prevTail = metadata -> tail ;
303
+ data .newRightlink = sublist .head ;
304
+
299
305
buffer = ReadBuffer (index , metadata -> tail );
300
306
LockBuffer (buffer , GIN_EXCLUSIVE );
301
307
page = BufferGetPage (buffer );
308
+
302
309
Assert (GinPageGetOpaque (page )-> rightlink == InvalidBlockNumber );
303
310
304
311
START_CRIT_SECTION ();
305
312
306
313
GinPageGetOpaque (page )-> rightlink = sublist .head ;
314
+
315
+ MarkBufferDirty (buffer );
316
+
307
317
metadata -> tail = sublist .tail ;
308
318
metadata -> tailFreeSize = sublist .tailFreeSize ;
309
319
310
320
metadata -> nPendingPages += sublist .nPendingPages ;
311
321
metadata -> nPendingHeapTuples += sublist .nPendingHeapTuples ;
312
-
313
- memcpy (& data .metadata , metadata , sizeof (GinMetaPageData ));
314
- data .newRightlink = sublist .head ;
315
-
316
- MarkBufferDirty (buffer );
317
322
}
318
323
}
319
324
else
320
325
{
321
326
/*
322
- * Insert into tail page, metapage is already locked
327
+ * Insert into tail page. Metapage is already locked
323
328
*/
324
-
325
329
OffsetNumber l ,
326
330
off ;
327
331
int i ,
@@ -331,6 +335,7 @@ ginHeapTupleFastInsert(Relation index, GinState *ginstate,
331
335
buffer = ReadBuffer (index , metadata -> tail );
332
336
LockBuffer (buffer , GIN_EXCLUSIVE );
333
337
page = BufferGetPage (buffer );
338
+
334
339
off = (PageIsEmpty (page )) ? FirstOffsetNumber :
335
340
OffsetNumberNext (PageGetMaxOffsetNumber (page ));
336
341
@@ -368,20 +373,24 @@ ginHeapTupleFastInsert(Relation index, GinState *ginstate,
368
373
off ++ ;
369
374
}
370
375
371
- metadata -> tailFreeSize -= collector -> sumsize + collector -> ntuples * sizeof (ItemIdData );
372
- memcpy (& data .metadata , metadata , sizeof (GinMetaPageData ));
376
+ Assert ((ptr - rdata [1 ].data ) <= collector -> sumsize );
377
+
378
+ metadata -> tailFreeSize = PageGetExactFreeSpace (page );
379
+
373
380
MarkBufferDirty (buffer );
374
381
}
375
382
376
383
/*
377
- * Make real write
384
+ * Write metabuffer, make xlog entry
378
385
*/
379
-
380
386
MarkBufferDirty (metabuffer );
387
+
381
388
if (!index -> rd_istemp )
382
389
{
383
390
XLogRecPtr recptr ;
384
391
392
+ memcpy (& data .metadata , metadata , sizeof (GinMetaPageData ));
393
+
385
394
recptr = XLogInsert (RM_GIN_ID , XLOG_GIN_UPDATE_META_PAGE , rdata );
386
395
PageSetLSN (metapage , recptr );
387
396
PageSetTLI (metapage , ThisTimeLineID );
@@ -552,7 +561,6 @@ shiftList(Relation index, Buffer metabuffer, BlockNumber newHead,
552
561
metadata -> nPendingPages = 0 ;
553
562
metadata -> nPendingHeapTuples = 0 ;
554
563
}
555
- memcpy (& data .metadata , metadata , sizeof (GinMetaPageData ));
556
564
557
565
MarkBufferDirty (metabuffer );
558
566
@@ -567,6 +575,8 @@ shiftList(Relation index, Buffer metabuffer, BlockNumber newHead,
567
575
{
568
576
XLogRecPtr recptr ;
569
577
578
+ memcpy (& data .metadata , metadata , sizeof (GinMetaPageData ));
579
+
570
580
recptr = XLogInsert (RM_GIN_ID , XLOG_GIN_DELETE_LISTPAGE , rdata );
571
581
PageSetLSN (metapage , recptr );
572
582
PageSetTLI (metapage , ThisTimeLineID );
0 commit comments