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

Commitd5497b9

Browse files
committed
Split off functions related to timeline history files and XLOG archiving.
This is just refactoring, to make the functions accessible outside xlog.c.A followup patch will make use of that, to allow fetching timeline historyfiles over streaming replication.
1 parent0899556 commitd5497b9

File tree

6 files changed

+1058
-929
lines changed

6 files changed

+1058
-929
lines changed

‎src/backend/access/transam/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ top_builddir = ../../../..
1313
include$(top_builddir)/src/Makefile.global
1414

1515
OBJS = clog.o transam.o varsup.o xact.o rmgr.o slru.o subtrans.o multixact.o\
16-
twophase.o twophase_rmgr.o xlog.o xlogfuncs.o xlogutils.o
16+
timeline.o twophase.o twophase_rmgr.o xlog.o xlogarchive.o xlogfuncs.o\
17+
xlogutils.o
1718

1819
include$(top_srcdir)/src/backend/common.mk
1920

‎src/backend/access/transam/timeline.c

Lines changed: 378 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,378 @@
1+
/*-------------------------------------------------------------------------
2+
*
3+
* timeline.c
4+
*Functions for reading and writing timeline history files.
5+
*
6+
* A timeline history file lists the timeline changes of the timeline, in
7+
* a simple text format. They are archived along with the WAL segments.
8+
*
9+
* The files are named like "<WAL segment>.history". For example, if the
10+
* database starts up and switches to timeline 5, while processing WAL
11+
* segment 000000030000002A00000006 (the old timeline was 3), the timeline
12+
* history file would be called "000000050000002A00000006.history".
13+
*
14+
* Each line in the file represents a timeline switch:
15+
*
16+
* <parentTLI> <xlogfname> <reason>
17+
*
18+
*parentTLIID of the parent timeline
19+
*xlogfnamefilename of the WAL segment where the switch happened
20+
*reasonhuman-readable explanation of why the timeline was changed
21+
*
22+
* The fields are separated by tabs. Lines beginning with # are comments, and
23+
* are ignored. Empty lines are also ignored.
24+
*
25+
* Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
26+
* Portions Copyright (c) 1994, Regents of the University of California
27+
*
28+
* src/backend/access/transam/timeline.c
29+
*
30+
*-------------------------------------------------------------------------
31+
*/
32+
33+
#include"postgres.h"
34+
35+
#include<stdio.h>
36+
#include<unistd.h>
37+
38+
#include"access/timeline.h"
39+
#include"access/xlog_internal.h"
40+
#include"access/xlogdefs.h"
41+
#include"storage/fd.h"
42+
43+
/*
44+
* Try to read a timeline's history file.
45+
*
46+
* If successful, return the list of component TLIs (the given TLI followed by
47+
* its ancestor TLIs).If we can't find the history file, assume that the
48+
* timeline has no parents, and return a list of just the specified timeline
49+
* ID.
50+
*/
51+
List*
52+
readTimeLineHistory(TimeLineIDtargetTLI)
53+
{
54+
List*result;
55+
charpath[MAXPGPATH];
56+
charhistfname[MAXFNAMELEN];
57+
charfline[MAXPGPATH];
58+
FILE*fd;
59+
60+
/* Timeline 1 does not have a history file, so no need to check */
61+
if (targetTLI==1)
62+
returnlist_make1_int((int)targetTLI);
63+
64+
if (InArchiveRecovery)
65+
{
66+
TLHistoryFileName(histfname,targetTLI);
67+
RestoreArchivedFile(path,histfname,"RECOVERYHISTORY",0);
68+
}
69+
else
70+
TLHistoryFilePath(path,targetTLI);
71+
72+
fd=AllocateFile(path,"r");
73+
if (fd==NULL)
74+
{
75+
if (errno!=ENOENT)
76+
ereport(FATAL,
77+
(errcode_for_file_access(),
78+
errmsg("could not open file \"%s\": %m",path)));
79+
/* Not there, so assume no parents */
80+
returnlist_make1_int((int)targetTLI);
81+
}
82+
83+
result=NIL;
84+
85+
/*
86+
* Parse the file...
87+
*/
88+
while (fgets(fline,sizeof(fline),fd)!=NULL)
89+
{
90+
/* skip leading whitespace and check for # comment */
91+
char*ptr;
92+
char*endptr;
93+
TimeLineIDtli;
94+
95+
for (ptr=fline;*ptr;ptr++)
96+
{
97+
if (!isspace((unsignedchar)*ptr))
98+
break;
99+
}
100+
if (*ptr=='\0'||*ptr=='#')
101+
continue;
102+
103+
/* expect a numeric timeline ID as first field of line */
104+
tli= (TimeLineID)strtoul(ptr,&endptr,0);
105+
if (endptr==ptr)
106+
ereport(FATAL,
107+
(errmsg("syntax error in history file: %s",fline),
108+
errhint("Expected a numeric timeline ID.")));
109+
110+
if (result&&
111+
tli <= (TimeLineID)linitial_int(result))
112+
ereport(FATAL,
113+
(errmsg("invalid data in history file: %s",fline),
114+
errhint("Timeline IDs must be in increasing sequence.")));
115+
116+
/* Build list with newest item first */
117+
result=lcons_int((int)tli,result);
118+
119+
/* we ignore the remainder of each line */
120+
}
121+
122+
FreeFile(fd);
123+
124+
if (result&&
125+
targetTLI <= (TimeLineID)linitial_int(result))
126+
ereport(FATAL,
127+
(errmsg("invalid data in history file \"%s\"",path),
128+
errhint("Timeline IDs must be less than child timeline's ID.")));
129+
130+
result=lcons_int((int)targetTLI,result);
131+
132+
ereport(DEBUG3,
133+
(errmsg_internal("history of timeline %u is %s",
134+
targetTLI,nodeToString(result))));
135+
136+
returnresult;
137+
}
138+
139+
/*
140+
* Probe whether a timeline history file exists for the given timeline ID
141+
*/
142+
bool
143+
existsTimeLineHistory(TimeLineIDprobeTLI)
144+
{
145+
charpath[MAXPGPATH];
146+
charhistfname[MAXFNAMELEN];
147+
FILE*fd;
148+
149+
/* Timeline 1 does not have a history file, so no need to check */
150+
if (probeTLI==1)
151+
return false;
152+
153+
if (InArchiveRecovery)
154+
{
155+
TLHistoryFileName(histfname,probeTLI);
156+
RestoreArchivedFile(path,histfname,"RECOVERYHISTORY",0);
157+
}
158+
else
159+
TLHistoryFilePath(path,probeTLI);
160+
161+
fd=AllocateFile(path,"r");
162+
if (fd!=NULL)
163+
{
164+
FreeFile(fd);
165+
return true;
166+
}
167+
else
168+
{
169+
if (errno!=ENOENT)
170+
ereport(FATAL,
171+
(errcode_for_file_access(),
172+
errmsg("could not open file \"%s\": %m",path)));
173+
return false;
174+
}
175+
}
176+
177+
/*
178+
* Find the newest existing timeline, assuming that startTLI exists.
179+
*
180+
* Note: while this is somewhat heuristic, it does positively guarantee
181+
* that (result + 1) is not a known timeline, and therefore it should
182+
* be safe to assign that ID to a new timeline.
183+
*/
184+
TimeLineID
185+
findNewestTimeLine(TimeLineIDstartTLI)
186+
{
187+
TimeLineIDnewestTLI;
188+
TimeLineIDprobeTLI;
189+
190+
/*
191+
* The algorithm is just to probe for the existence of timeline history
192+
* files. XXX is it useful to allow gaps in the sequence?
193+
*/
194+
newestTLI=startTLI;
195+
196+
for (probeTLI=startTLI+1;;probeTLI++)
197+
{
198+
if (existsTimeLineHistory(probeTLI))
199+
{
200+
newestTLI=probeTLI;/* probeTLI exists */
201+
}
202+
else
203+
{
204+
/* doesn't exist, assume we're done */
205+
break;
206+
}
207+
}
208+
209+
returnnewestTLI;
210+
}
211+
212+
/*
213+
* Create a new timeline history file.
214+
*
215+
*newTLI: ID of the new timeline
216+
*parentTLI: ID of its immediate parent
217+
*endTLI et al: ID of the last used WAL file, for annotation purposes
218+
*reason: human-readable explanation of why the timeline was switched
219+
*
220+
* Currently this is only used at the end recovery, and so there are no locking
221+
* considerations.But we should be just as tense as XLogFileInit to avoid
222+
* emplacing a bogus file.
223+
*/
224+
void
225+
writeTimeLineHistory(TimeLineIDnewTLI,TimeLineIDparentTLI,
226+
TimeLineIDendTLI,XLogSegNoendLogSegNo,char*reason)
227+
{
228+
charpath[MAXPGPATH];
229+
chartmppath[MAXPGPATH];
230+
charhistfname[MAXFNAMELEN];
231+
charxlogfname[MAXFNAMELEN];
232+
charbuffer[BLCKSZ];
233+
intsrcfd;
234+
intfd;
235+
intnbytes;
236+
237+
Assert(newTLI>parentTLI);/* else bad selection of newTLI */
238+
239+
/*
240+
* Write into a temp file name.
241+
*/
242+
snprintf(tmppath,MAXPGPATH,XLOGDIR"/xlogtemp.%d", (int)getpid());
243+
244+
unlink(tmppath);
245+
246+
/* do not use get_sync_bit() here --- want to fsync only at end of fill */
247+
fd=BasicOpenFile(tmppath,O_RDWR |O_CREAT |O_EXCL,
248+
S_IRUSR |S_IWUSR);
249+
if (fd<0)
250+
ereport(ERROR,
251+
(errcode_for_file_access(),
252+
errmsg("could not create file \"%s\": %m",tmppath)));
253+
254+
/*
255+
* If a history file exists for the parent, copy it verbatim
256+
*/
257+
if (InArchiveRecovery)
258+
{
259+
TLHistoryFileName(histfname,parentTLI);
260+
RestoreArchivedFile(path,histfname,"RECOVERYHISTORY",0);
261+
}
262+
else
263+
TLHistoryFilePath(path,parentTLI);
264+
265+
srcfd=BasicOpenFile(path,O_RDONLY,0);
266+
if (srcfd<0)
267+
{
268+
if (errno!=ENOENT)
269+
ereport(ERROR,
270+
(errcode_for_file_access(),
271+
errmsg("could not open file \"%s\": %m",path)));
272+
/* Not there, so assume parent has no parents */
273+
}
274+
else
275+
{
276+
for (;;)
277+
{
278+
errno=0;
279+
nbytes= (int)read(srcfd,buffer,sizeof(buffer));
280+
if (nbytes<0||errno!=0)
281+
ereport(ERROR,
282+
(errcode_for_file_access(),
283+
errmsg("could not read file \"%s\": %m",path)));
284+
if (nbytes==0)
285+
break;
286+
errno=0;
287+
if ((int)write(fd,buffer,nbytes)!=nbytes)
288+
{
289+
intsave_errno=errno;
290+
291+
/*
292+
* If we fail to make the file, delete it to release disk
293+
* space
294+
*/
295+
unlink(tmppath);
296+
297+
/*
298+
* if write didn't set errno, assume problem is no disk space
299+
*/
300+
errno=save_errno ?save_errno :ENOSPC;
301+
302+
ereport(ERROR,
303+
(errcode_for_file_access(),
304+
errmsg("could not write to file \"%s\": %m",tmppath)));
305+
}
306+
}
307+
close(srcfd);
308+
}
309+
310+
/*
311+
* Append one line with the details of this timeline split.
312+
*
313+
* If we did have a parent file, insert an extra newline just in case the
314+
* parent file failed to end with one.
315+
*/
316+
XLogFileName(xlogfname,endTLI,endLogSegNo);
317+
318+
snprintf(buffer,sizeof(buffer),
319+
"%s%u\t%s\t%s\n",
320+
(srcfd<0) ?"" :"\n",
321+
parentTLI,
322+
xlogfname,
323+
reason);
324+
325+
nbytes=strlen(buffer);
326+
errno=0;
327+
if ((int)write(fd,buffer,nbytes)!=nbytes)
328+
{
329+
intsave_errno=errno;
330+
331+
/*
332+
* If we fail to make the file, delete it to release disk space
333+
*/
334+
unlink(tmppath);
335+
/* if write didn't set errno, assume problem is no disk space */
336+
errno=save_errno ?save_errno :ENOSPC;
337+
338+
ereport(ERROR,
339+
(errcode_for_file_access(),
340+
errmsg("could not write to file \"%s\": %m",tmppath)));
341+
}
342+
343+
if (pg_fsync(fd)!=0)
344+
ereport(ERROR,
345+
(errcode_for_file_access(),
346+
errmsg("could not fsync file \"%s\": %m",tmppath)));
347+
348+
if (close(fd))
349+
ereport(ERROR,
350+
(errcode_for_file_access(),
351+
errmsg("could not close file \"%s\": %m",tmppath)));
352+
353+
354+
/*
355+
* Now move the completed history file into place with its final name.
356+
*/
357+
TLHistoryFilePath(path,newTLI);
358+
359+
/*
360+
* Prefer link() to rename() here just to be really sure that we don't
361+
* overwrite an existing logfile. However, there shouldn't be one, so
362+
* rename() is an acceptable substitute except for the truly paranoid.
363+
*/
364+
#ifHAVE_WORKING_LINK
365+
if (link(tmppath,path)<0)
366+
ereport(ERROR,
367+
(errcode_for_file_access(),
368+
errmsg("could not link file \"%s\" to \"%s\": %m",
369+
tmppath,path)));
370+
unlink(tmppath);
371+
#else
372+
if (rename(tmppath,path)<0)
373+
ereport(ERROR,
374+
(errcode_for_file_access(),
375+
errmsg("could not rename file \"%s\" to \"%s\": %m",
376+
tmppath,path)));
377+
#endif
378+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp