Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit7db0cd2

Browse files
committed
Set PD_ALL_VISIBLE and visibility map bits in COPY FREEZE
Make sure COPY FREEZE marks the pages as PD_ALL_VISIBLE and updates thevisibility map. Until now we only marked individual tuples as frozen,but page-level flags were not updated, so the first VACUUM after theCOPY FREEZE had to rewrite the whole table.This is a fairly old patch, and multiple people worked on it. The firstversion was written by Jeff Janes, and then reworked by Pavan Deolaseeand Anastasia Lubennikova.Author: Anastasia Lubennikova, Pavan Deolasee, Jeff JanesReviewed-by: Kuntal Ghosh, Jeff Janes, Tomas Vondra, Masahiko Sawada, Andres Freund, Ibrar Ahmed, Robert Haas, Tatsuro Ishii, Darafei PraliaskouskiDiscussion:https://postgr.es/m/CABOikdN-ptGv0mZntrK2Q8OtfUuAjqaYMGmkdU1dCKFtUxVLrg@mail.gmail.comDiscussion:https://postgr.es/m/CAMkU%3D1w3osJJ2FneELhhNRLxfZitDgp9FPHee08NT2FQFmz_pQ%40mail.gmail.com
1 parent0c7d3bb commit7db0cd2

File tree

5 files changed

+230
-8
lines changed

5 files changed

+230
-8
lines changed

‎contrib/pg_visibility/expected/pg_visibility.out

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,69 @@ select pg_truncate_visibility_map('test_partition');
179179

180180
(1 row)
181181

182+
-- test copy freeze
183+
create table copyfreeze (a int, b char(1500));
184+
-- load all rows via COPY FREEZE and ensure that all pages are set all-visible
185+
-- and all-frozen.
186+
begin;
187+
truncate copyfreeze;
188+
copy copyfreeze from stdin freeze;
189+
commit;
190+
select * from pg_visibility_map('copyfreeze');
191+
blkno | all_visible | all_frozen
192+
-------+-------------+------------
193+
0 | t | t
194+
1 | t | t
195+
2 | t | t
196+
(3 rows)
197+
198+
select * from pg_check_frozen('copyfreeze');
199+
t_ctid
200+
--------
201+
(0 rows)
202+
203+
-- load half the rows via regular COPY and rest via COPY FREEZE. The pages
204+
-- which are touched by regular COPY must not be set all-visible/all-frozen. On
205+
-- the other hand, pages allocated by COPY FREEZE should be marked
206+
-- all-frozen/all-visible.
207+
begin;
208+
truncate copyfreeze;
209+
copy copyfreeze from stdin;
210+
copy copyfreeze from stdin freeze;
211+
commit;
212+
select * from pg_visibility_map('copyfreeze');
213+
blkno | all_visible | all_frozen
214+
-------+-------------+------------
215+
0 | f | f
216+
1 | f | f
217+
2 | t | t
218+
(3 rows)
219+
220+
select * from pg_check_frozen('copyfreeze');
221+
t_ctid
222+
--------
223+
(0 rows)
224+
225+
-- Try a mix of regular COPY and COPY FREEZE.
226+
begin;
227+
truncate copyfreeze;
228+
copy copyfreeze from stdin freeze;
229+
copy copyfreeze from stdin;
230+
copy copyfreeze from stdin freeze;
231+
commit;
232+
select * from pg_visibility_map('copyfreeze');
233+
blkno | all_visible | all_frozen
234+
-------+-------------+------------
235+
0 | t | t
236+
1 | f | f
237+
2 | t | t
238+
(3 rows)
239+
240+
select * from pg_check_frozen('copyfreeze');
241+
t_ctid
242+
--------
243+
(0 rows)
244+
182245
-- cleanup
183246
drop table test_partitioned;
184247
drop view test_view;
@@ -188,3 +251,4 @@ drop server dummy_server;
188251
drop foreign data wrapper dummy;
189252
drop materialized view matview_visibility_test;
190253
drop table regular_table;
254+
drop table copyfreeze;

‎contrib/pg_visibility/sql/pg_visibility.sql

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,82 @@ select count(*) > 0 from pg_visibility_map_summary('test_partition');
9494
select*from pg_check_frozen('test_partition');-- hopefully none
9595
select pg_truncate_visibility_map('test_partition');
9696

97+
-- test copy freeze
98+
createtablecopyfreeze (aint, bchar(1500));
99+
100+
-- load all rows via COPY FREEZE and ensure that all pages are set all-visible
101+
-- and all-frozen.
102+
begin;
103+
truncate copyfreeze;
104+
copy copyfreezefrom stdin freeze;
105+
1'1'
106+
2'2'
107+
3'3'
108+
4'4'
109+
5'5'
110+
6'6'
111+
7'7'
112+
8'8'
113+
9'9'
114+
10'10'
115+
11'11'
116+
12'12'
117+
\.
118+
commit;
119+
select*from pg_visibility_map('copyfreeze');
120+
select*from pg_check_frozen('copyfreeze');
121+
122+
-- load half the rows via regular COPY and rest via COPY FREEZE. The pages
123+
-- which are touched by regular COPY must not be set all-visible/all-frozen. On
124+
-- the other hand, pages allocated by COPY FREEZE should be marked
125+
-- all-frozen/all-visible.
126+
begin;
127+
truncate copyfreeze;
128+
copy copyfreezefrom stdin;
129+
1'1'
130+
2'2'
131+
3'3'
132+
4'4'
133+
5'5'
134+
6'6'
135+
\.
136+
copy copyfreezefrom stdin freeze;
137+
7'7'
138+
8'8'
139+
9'9'
140+
10'10'
141+
11'11'
142+
12'12'
143+
\.
144+
commit;
145+
select*from pg_visibility_map('copyfreeze');
146+
select*from pg_check_frozen('copyfreeze');
147+
148+
-- Try a mix of regular COPY and COPY FREEZE.
149+
begin;
150+
truncate copyfreeze;
151+
copy copyfreezefrom stdin freeze;
152+
1'1'
153+
2'2'
154+
3'3'
155+
4'4'
156+
5'5'
157+
\.
158+
copy copyfreezefrom stdin;
159+
6'6'
160+
\.
161+
copy copyfreezefrom stdin freeze;
162+
7'7'
163+
8'8'
164+
9'9'
165+
10'10'
166+
11'11'
167+
12'12'
168+
\.
169+
commit;
170+
select*from pg_visibility_map('copyfreeze');
171+
select*from pg_check_frozen('copyfreeze');
172+
97173
-- cleanup
98174
droptable test_partitioned;
99175
dropview test_view;
@@ -103,3 +179,4 @@ drop server dummy_server;
103179
drop foreign data wrapper dummy;
104180
drop materialized view matview_visibility_test;
105181
droptable regular_table;
182+
droptable copyfreeze;

‎src/backend/access/heap/heapam.c

Lines changed: 69 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2121,6 +2121,7 @@ heap_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples,
21212121
intndone;
21222122
PGAlignedBlockscratch;
21232123
Pagepage;
2124+
Buffervmbuffer=InvalidBuffer;
21242125
boolneedwal;
21252126
SizesaveFreeSpace;
21262127
boolneed_tuple_data=RelationIsLogicallyLogged(relation);
@@ -2175,21 +2176,30 @@ heap_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples,
21752176
while (ndone<ntuples)
21762177
{
21772178
Bufferbuffer;
2178-
Buffervmbuffer=InvalidBuffer;
2179+
boolstarting_with_empty_page;
21792180
boolall_visible_cleared= false;
2181+
boolall_frozen_set= false;
21802182
intnthispage;
21812183

21822184
CHECK_FOR_INTERRUPTS();
21832185

21842186
/*
21852187
* Find buffer where at least the next tuple will fit. If the page is
21862188
* all-visible, this will also pin the requisite visibility map page.
2189+
*
2190+
* Also pin visibility map page if COPY FREEZE inserts tuples into an
2191+
* empty page. See all_frozen_set below.
21872192
*/
21882193
buffer=RelationGetBufferForTuple(relation,heaptuples[ndone]->t_len,
21892194
InvalidBuffer,options,bistate,
21902195
&vmbuffer,NULL);
21912196
page=BufferGetPage(buffer);
21922197

2198+
starting_with_empty_page=PageGetMaxOffsetNumber(page)==0;
2199+
2200+
if (starting_with_empty_page&& (options&HEAP_INSERT_FROZEN))
2201+
all_frozen_set= true;
2202+
21932203
/* NO EREPORT(ERROR) from here till changes are logged */
21942204
START_CRIT_SECTION();
21952205

@@ -2223,14 +2233,23 @@ heap_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples,
22232233
log_heap_new_cid(relation,heaptup);
22242234
}
22252235

2226-
if (PageIsAllVisible(page))
2236+
/*
2237+
* If the page is all visible, need to clear that, unless we're only
2238+
* going to add further frozen rows to it.
2239+
*
2240+
* If we're only adding already frozen rows to a previously empty
2241+
* page, mark it as all-visible.
2242+
*/
2243+
if (PageIsAllVisible(page)&& !(options&HEAP_INSERT_FROZEN))
22272244
{
22282245
all_visible_cleared= true;
22292246
PageClearAllVisible(page);
22302247
visibilitymap_clear(relation,
22312248
BufferGetBlockNumber(buffer),
22322249
vmbuffer,VISIBILITYMAP_VALID_BITS);
22332250
}
2251+
elseif (all_frozen_set)
2252+
PageSetAllVisible(page);
22342253

22352254
/*
22362255
* XXX Should we set PageSetPrunable on this page ? See heap_insert()
@@ -2254,8 +2273,7 @@ heap_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples,
22542273
* If the page was previously empty, we can reinit the page
22552274
* instead of restoring the whole thing.
22562275
*/
2257-
init= (ItemPointerGetOffsetNumber(&(heaptuples[ndone]->t_self))==FirstOffsetNumber&&
2258-
PageGetMaxOffsetNumber(page)==FirstOffsetNumber+nthispage-1);
2276+
init=starting_with_empty_page;
22592277

22602278
/* allocate xl_heap_multi_insert struct from the scratch area */
22612279
xlrec= (xl_heap_multi_insert*)scratchptr;
@@ -2273,7 +2291,15 @@ heap_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples,
22732291
/* the rest of the scratch space is used for tuple data */
22742292
tupledata=scratchptr;
22752293

2276-
xlrec->flags=all_visible_cleared ?XLH_INSERT_ALL_VISIBLE_CLEARED :0;
2294+
/* check that the mutually exclusive flags are not both set */
2295+
Assert (!(all_visible_cleared&&all_frozen_set));
2296+
2297+
xlrec->flags=0;
2298+
if (all_visible_cleared)
2299+
xlrec->flags=XLH_INSERT_ALL_VISIBLE_CLEARED;
2300+
if (all_frozen_set)
2301+
xlrec->flags=XLH_INSERT_ALL_FROZEN_SET;
2302+
22772303
xlrec->ntuples=nthispage;
22782304

22792305
/*
@@ -2347,13 +2373,40 @@ heap_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples,
23472373

23482374
END_CRIT_SECTION();
23492375

2350-
UnlockReleaseBuffer(buffer);
2351-
if (vmbuffer!=InvalidBuffer)
2352-
ReleaseBuffer(vmbuffer);
2376+
/*
2377+
* If we've frozen everything on the page, update the visibilitymap.
2378+
* We're already holding pin on the vmbuffer.
2379+
*/
2380+
if (all_frozen_set)
2381+
{
2382+
Assert(PageIsAllVisible(page));
2383+
Assert(visibilitymap_pin_ok(BufferGetBlockNumber(buffer),vmbuffer));
23532384

2385+
/*
2386+
* It's fine to use InvalidTransactionId here - this is only used
2387+
* when HEAP_INSERT_FROZEN is specified, which intentionally
2388+
* violates visibility rules.
2389+
*/
2390+
visibilitymap_set(relation,BufferGetBlockNumber(buffer),buffer,
2391+
InvalidXLogRecPtr,vmbuffer,
2392+
InvalidTransactionId,
2393+
VISIBILITYMAP_ALL_VISIBLE |VISIBILITYMAP_ALL_FROZEN);
2394+
}
2395+
2396+
UnlockReleaseBuffer(buffer);
23542397
ndone+=nthispage;
2398+
2399+
/*
2400+
* NB: Only release vmbuffer after inserting all tuples - it's fairly
2401+
* likely that we'll insert into subsequent heap pages that are likely
2402+
* to use the same vm page.
2403+
*/
23552404
}
23562405

2406+
/* We're done with inserting all tuples, so release the last vmbuffer. */
2407+
if (vmbuffer!=InvalidBuffer)
2408+
ReleaseBuffer(vmbuffer);
2409+
23572410
/*
23582411
* We're done with the actual inserts. Check for conflicts again, to
23592412
* ensure that all rw-conflicts in to these inserts are detected. Without
@@ -8725,6 +8778,10 @@ heap_xlog_insert(XLogReaderState *record)
87258778
if (xlrec->flags&XLH_INSERT_ALL_VISIBLE_CLEARED)
87268779
PageClearAllVisible(page);
87278780

8781+
/* XLH_INSERT_ALL_FROZEN_SET implies that all tuples are visible */
8782+
if (xlrec->flags&XLH_INSERT_ALL_FROZEN_SET)
8783+
PageSetAllVisible(page);
8784+
87288785
MarkBufferDirty(buffer);
87298786
}
87308787
if (BufferIsValid(buffer))
@@ -8775,6 +8832,10 @@ heap_xlog_multi_insert(XLogReaderState *record)
87758832

87768833
XLogRecGetBlockTag(record,0,&rnode,NULL,&blkno);
87778834

8835+
/* check that the mutually exclusive flags are not both set */
8836+
Assert (!((xlrec->flags&XLH_INSERT_ALL_VISIBLE_CLEARED)&&
8837+
(xlrec->flags&XLH_INSERT_ALL_FROZEN_SET)));
8838+
87788839
/*
87798840
* The visibility map may need to be fixed even if the heap page is
87808841
* already up-to-date.

‎src/backend/access/heap/hio.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,14 @@ RelationGetBufferForTuple(Relation relation, Size len,
433433
buffer=ReadBufferBI(relation,targetBlock,RBM_NORMAL,bistate);
434434
if (PageIsAllVisible(BufferGetPage(buffer)))
435435
visibilitymap_pin(relation,targetBlock,vmbuffer);
436+
437+
/*
438+
* If the page is empty, pin vmbuffer to set all_frozen bit later.
439+
*/
440+
if ((options&HEAP_INSERT_FROZEN)&&
441+
(PageGetMaxOffsetNumber(BufferGetPage(buffer))==0))
442+
visibilitymap_pin(relation,targetBlock,vmbuffer);
443+
436444
LockBuffer(buffer,BUFFER_LOCK_EXCLUSIVE);
437445
}
438446
elseif (otherBlock==targetBlock)
@@ -619,6 +627,15 @@ RelationGetBufferForTuple(Relation relation, Size len,
619627
PageInit(page,BufferGetPageSize(buffer),0);
620628
MarkBufferDirty(buffer);
621629

630+
/*
631+
* The page is empty, pin vmbuffer to set all_frozen bit.
632+
*/
633+
if (options&HEAP_INSERT_FROZEN)
634+
{
635+
Assert(PageGetMaxOffsetNumber(BufferGetPage(buffer))==0);
636+
visibilitymap_pin(relation,BufferGetBlockNumber(buffer),vmbuffer);
637+
}
638+
622639
/*
623640
* Release the file-extension lock; it's now OK for someone else to extend
624641
* the relation some more.

‎src/include/access/heapam_xlog.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@
6969
#defineXLH_INSERT_CONTAINS_NEW_TUPLE(1<<3)
7070
#defineXLH_INSERT_ON_TOAST_RELATION(1<<4)
7171

72+
/* all_frozen_set always implies all_visible_set */
73+
#defineXLH_INSERT_ALL_FROZEN_SET(1<<5)
74+
7275
/*
7376
* xl_heap_update flag values, 8 bits are available.
7477
*/

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp