PostgreSQL 소스 코드 해독 (114) - 백 엔 드 프로 세 스 \ # 2 (checkpointer 프로 세 스 \ # 1)
데이터 구조
CheckPoint CheckPoint XLOG 레코드 구조 체.
/*
* Body of CheckPoint XLOG records. This is declared here because we keep
* a copy of the latest one in pg_control for possible disaster recovery.
* Changing this struct requires a PG_CONTROL_VERSION bump.
* CheckPoint XLOG record .
* pg_control ,
* 。
* PG_CONTROL_VERSION bump。
*/
typedef struct CheckPoint
{
// CheckPoint RecPtr( REDO )
XLogRecPtr redo; /* next RecPtr available when we began to
* create CheckPoint (i.e. REDO start point) */
//
TimeLineID ThisTimeLineID; /* current TLI */
// ( , )
TimeLineID PrevTimeLineID; /* previous TLI, if this record begins a new
* timeline (equals ThisTimeLineID otherwise) */
// full-page-write
bool fullPageWrites; /* current full_page_writes */
//nextXid
uint32 nextXidEpoch; /* higher-order bits of nextXid */
// free XID
TransactionId nextXid; /* next free XID */
// free OID
Oid nextOid; /* next free OID */
// fredd MultiXactId
MultiXactId nextMulti; /* next free MultiXactId */
// MultiXact
MultiXactOffset nextMultiOffset; /* next free MultiXact offset */
// datfrozenxid
TransactionId oldestXid; /* cluster-wide minimum datfrozenxid */
// datfrozenxid database
Oid oldestXidDB; /* database with minimum datfrozenxid */
// datminmxid
MultiXactId oldestMulti; /* cluster-wide minimum datminmxid */
// datminmxid database
Oid oldestMultiDB; /* database with minimum datminmxid */
//checkpoint
pg_time_t time; /* time stamp of checkpoint */
// Xid
TransactionId oldestCommitTsXid; /* oldest Xid with valid commit
* timestamp */
// Xid
TransactionId newestCommitTsXid; /* newest Xid with valid commit
* timestamp */
/*
* Oldest XID still running. This is only needed to initialize hot standby
* mode from an online checkpoint, so we only bother calculating this for
* online checkpoints and only when wal_level is replica. Otherwise it's
* set to InvalidTransactionId.
* XID 。
* online checkpoint , ,
* wal_level replica 。
* InvalidTransactionId。
*/
TransactionId oldestActiveXid;
} CheckPoint;
/* XLOG info values for XLOG rmgr */
#define XLOG_CHECKPOINT_SHUTDOWN 0x00
#define XLOG_CHECKPOINT_ONLINE 0x10
#define XLOG_NOOP 0x20
#define XLOG_NEXTOID 0x30
#define XLOG_SWITCH 0x40
#define XLOG_BACKUP_END 0x50
#define XLOG_PARAMETER_CHANGE 0x60
#define XLOG_RESTORE_POINT 0x70
#define XLOG_FPW_CHANGE 0x80
#define XLOG_END_OF_RECOVERY 0x90
#define XLOG_FPI_FOR_HINT 0xA0
#define XLOG_FPI 0xB0
Checkpointer Shmem checkpointer 프로 세 스 와 다른 배경 프로 세 스 간 에 통신 하 는 공유 메모리 구조 입 니 다.
/*----------
* Shared memory area for communication between checkpointer and backends
* checkpointer .
*
* The ckpt counters allow backends to watch for completion of a checkpoint
* request they send. Here's how it works:
* * At start of a checkpoint, checkpointer reads (and clears) the request
* flags and increments ckpt_started, while holding ckpt_lck.
* * On completion of a checkpoint, checkpointer sets ckpt_done to
* equal ckpt_started.
* * On failure of a checkpoint, checkpointer increments ckpt_failed
* and sets ckpt_done to equal ckpt_started.
* ckpt checkpoint . :
* * checkpoint ,checkpointer ckpt_lck ,
* ( ) ckpt_started .
* * checkpoint ,checkpointer ckpt_done ckpt_started.
* * checkpoint ,checkpointer ckpt_failed , ckpt_done ckpt_started.
*
* The algorithm for backends is:
* 1. Record current values of ckpt_failed and ckpt_started, and
* set request flags, while holding ckpt_lck.
* 2. Send signal to request checkpoint.
* 3. Sleep until ckpt_started changes. Now you know a checkpoint has
* begun since you started this algorithm (although *not* that it was
* specifically initiated by your signal), and that it is using your flags.
* 4. Record new value of ckpt_started.
* 5. Sleep until ckpt_done >= saved value of ckpt_started. (Use modulo
* arithmetic here in case counters wrap around.) Now you know a
* checkpoint has started and completed, but not whether it was
* successful.
* 6. If ckpt_failed is different from the originally saved value,
* assume request failed; otherwise it was definitely successful.
* :
* 1. ckpt_lck , ckpt_failed ckpt_started , .
* 2. , checkpoint.
* 3. ckpt_started .
* ( * * ), 。
* 4. ckpt_started .
* 5. , ckpt_done >= ckpt_started ( ). checkpoint & , checkpoint .
* 6. ckpt_failed , , .
*
* ckpt_flags holds the OR of the checkpoint request flags sent by all
* requesting backends since the last checkpoint start. The flags are
* chosen so that OR'ing is the correct way to combine multiple requests.
* ckpt_flags OR 。
* , OR'ing 。
*
* num_backend_writes is used to count the number of buffer writes performed
* by user backend processes. This counter should be wide enough that it
* can't overflow during a single processing cycle. num_backend_fsync
* counts the subset of those writes that also had to do their own fsync,
* because the checkpointer failed to absorb their request.
* num_backend_writes .
* , .
* num_backend_fsync fsync ,
* checkpointer 。
*
* The requests array holds fsync requests sent by backends and not yet
* absorbed by the checkpointer.
* checkpointer fsync .
*
* Unlike the checkpoint fields, num_backend_writes, num_backend_fsync, and
* the requests fields are protected by CheckpointerCommLock.
* checkpoint ,num_backend_writes/num_backend_fsync CheckpointerCommLock .
*
*----------
*/
typedef struct
{
RelFileNode rnode;// / /Relation
ForkNumber forknum;//fork
BlockNumber segno; /* see md.c for special values */
/* might add a real request-type field later; not needed yet */
} CheckpointerRequest;
typedef struct
{
//checkpoint pid( 0 )
pid_t checkpointer_pid; /* PID (0 if not started) */
// ckpt_*
slock_t ckpt_lck; /* protects all the ckpt_* fields */
// checkpoint
int ckpt_started; /* advances when checkpoint starts */
// checkpoint
int ckpt_done; /* advances when checkpoint done */
// checkpoint
int ckpt_failed; /* advances when checkpoint fails */
// , xlog.h
int ckpt_flags; /* checkpoint flags, as defined in xlog.h */
//
uint32 num_backend_writes; /* counts user backend buffer writes */
// fsync
uint32 num_backend_fsync; /* counts user backend fsync calls */
//
int num_requests; /* current # of requests */
//
int max_requests; /* allocated array size */
//
CheckpointerRequest requests[FLEXIBLE_ARRAY_MEMBER];
} CheckpointerShmemStruct;
// (CheckpointerShmemStruct )
static CheckpointerShmemStruct *CheckpointerShmem;
2. 소스 코드 해독
Checkpointer Main 함 수 는 checkpointer 프로 세 스 의 입구 입 니 다. 이 함 수 는 먼저 신호 설정 컨트롤 러 (예 를 들 어 자바 OO 개발 에 익숙 하고 이러한 쓰기 가 낯 설 지 않 아야 합 니 다) 를 만 든 다음 프로 세 스 의 메모리 컨 텍스트 를 만 들 고 순환 (forever) 에 들 어가 '적당 한' 때 checkpoint 를 실행 합 니 다.
/*
* Main entry point for checkpointer process
* checkpointer .
*
* This is invoked from AuxiliaryProcessMain, which has already created the
* basic execution environment, but not enabled signals yet.
* AuxiliaryProcessMain , , .
*/
void
CheckpointerMain(void)
{
sigjmp_buf local_sigjmp_buf;
MemoryContext checkpointer_context;
CheckpointerShmem->checkpointer_pid = MyProcPid;
// ( Java OO , )
/*
* Properly accept or ignore signals the postmaster might send us
* postmaster .
*
* Note: we deliberately ignore SIGTERM, because during a standard Unix
* system shutdown cycle, init will SIGTERM all processes at once. We
* want to wait for the backends to exit, whereupon the postmaster will
* tell us it's okay to shut down (via SIGUSR2).
* : SIGTERM, Unix ,
* init SIGTERM 。
* , postmaster checkpointer ( SIGUSR2)。
*/
// ,
pqsignal(SIGHUP, ChkptSigHupHandler); /* set flag to read config file */
// checkpoint
pqsignal(SIGINT, ReqCheckpointHandler); /* request checkpoint */
// SIGTERM
pqsignal(SIGTERM, SIG_IGN); /* ignore SIGTERM */
//
pqsignal(SIGQUIT, chkpt_quickdie); /* hard crash time */
// SIGALRM & SIGPIPE
pqsignal(SIGALRM, SIG_IGN);
pqsignal(SIGPIPE, SIG_IGN);
pqsignal(SIGUSR1, chkpt_sigusr1_handler);
//
pqsignal(SIGUSR2, ReqShutdownHandler); /* request shutdown */
/*
* Reset some signals that are accepted by postmaster but not here
* postmaster
*/
pqsignal(SIGCHLD, SIG_DFL);
/* We allow SIGQUIT (quickdie) at all times */
// SIGQUIT
sigdelset(&BlockSig, SIGQUIT);
/*
* Initialize so that first time-driven event happens at the correct time.
* .
*/
last_checkpoint_time = last_xlog_switch_time = (pg_time_t) time(NULL);
/*
* Create a memory context that we will do all our work in. We do this so
* that we can reset the context during error recovery and thereby avoid
* possible memory leaks. Formerly this code just ran in
* TopMemoryContext, but resetting that would be a really bad idea.
* .
* .
*
*/
checkpointer_context = AllocSetContextCreate(TopMemoryContext,
"Checkpointer",
ALLOCSET_DEFAULT_SIZES);
MemoryContextSwitchTo(checkpointer_context);
/*
* If an exception is encountered, processing resumes here.
* , .
*
* See notes in postgres.c about the design of this coding.
* postgres.c
*/
if (sigsetjmp(local_sigjmp_buf, 1) != 0)
{
/* Since not using PG_TRY, must reset error stack by hand */
// PG_TRY,
error_context_stack = NULL;
/* Prevent interrupts while cleaning up */
//
HOLD_INTERRUPTS();
/* Report the error to the server log */
//
EmitErrorReport();
/*
* These operations are really just a minimal subset of
* AbortTransaction(). We don't have very many resources to worry
* about in checkpointer, but we do have LWLocks, buffers, and temp
* files.
* AbortTransaction() .
* checkpointer , LWLocks/
*/
LWLockReleaseAll();
ConditionVariableCancelSleep();
pgstat_report_wait_end();
AbortBufferIO();
UnlockBuffers();
ReleaseAuxProcessResources(false);
AtEOXact_Buffers(false);
AtEOXact_SMgr();
AtEOXact_Files(false);
AtEOXact_HashTables(false);
/* Warn any waiting backends that the checkpoint failed. */
// :checkpoint
if (ckpt_active)
{
SpinLockAcquire(&CheckpointerShmem->ckpt_lck);
CheckpointerShmem->ckpt_failed++;
CheckpointerShmem->ckpt_done = CheckpointerShmem->ckpt_started;
SpinLockRelease(&CheckpointerShmem->ckpt_lck);
ckpt_active = false;
}
/*
* Now return to normal top-level context and clear ErrorContext for
* next time.
* , checkpoint ErrorContext
*/
MemoryContextSwitchTo(checkpointer_context);
FlushErrorState();
/* Flush any leaked data in the top-level context */
//
MemoryContextResetAndDeleteChildren(checkpointer_context);
/* Now we can allow interrupts again */
//
RESUME_INTERRUPTS();
/*
* Sleep at least 1 second after any error. A write error is likely
* to be repeated, and we don't want to be filling the error logs as
* fast as we can.
* , 1s.
* , , 1s.
*/
pg_usleep(1000000L);
/*
* Close all open files after any error. This is helpful on Windows,
* where holding deleted files open causes various strange errors.
* It's not clear we need it elsewhere, but shouldn't hurt.
* , .
* Windows , .
* , 。
*/
smgrcloseall();
}
/* We can now handle ereport(ERROR) */
// ereport(ERROR) .
PG_exception_stack = &local_sigjmp_buf;
/*
* Unblock signals (they were blocked when the postmaster forked us)
* ( postmaster fork , )
*/
PG_SETMASK(&UnBlockSig);
/*
* Ensure all shared memory values are set correctly for the config. Doing
* this here ensures no race conditions from other concurrent updaters.
* .
* .
*/
UpdateSharedMemoryConfig();
/*
* Advertise our latch that backends can use to wake us up while we're
* sleeping.
* latch, latch .
*/
ProcGlobal->checkpointerLatch = &MyProc->procLatch;
/*
* Loop forever
* , , ...
*/
for (;;)
{
bool do_checkpoint = false;// checkpoint
int flags = 0;//
pg_time_t now;//
int elapsed_secs;//
int cur_timeout;//timeout
/* Clear any already-pending wakeups */
ResetLatch(MyLatch);
/*
* Process any requests or signals received recently.
*
*/
AbsorbFsyncRequests();
if (got_SIGHUP)//
{
got_SIGHUP = false;
ProcessConfigFile(PGC_SIGHUP);
/*
* Checkpointer is the last process to shut down, so we ask it to
* hold the keys for a range of other tasks required most of which
* have nothing to do with checkpointing at all.
* Checkpointer , ,
* .
*
* For various reasons, some config values can change dynamically
* so the primary copy of them is held in shared memory to make
* sure all backends see the same value. We make Checkpointer
* responsible for updating the shared memory copy if the
* parameter setting changes because of SIGHUP.
* , ,
* .
* SIGHUP , Checkpointer .
*/
UpdateSharedMemoryConfig();
}
if (checkpoint_requested)
{
// checkpoint
checkpoint_requested = false;//
do_checkpoint = true;// checkpoint
BgWriterStats.m_requested_checkpoints++;//
}
if (shutdown_requested)
{
//
/*
* From here on, elog(ERROR) should end with exit(1), not send
* control back to the sigsetjmp block above
* , ( ) exit(1) , sigsetjmp
*/
ExitOnAnyError = true;
/* Close down the database */
//
ShutdownXLOG(0, 0);
/* Normal exit from the checkpointer is here */
//checkpointer
proc_exit(0); /* done */
}
/*
* Force a checkpoint if too much time has elapsed since the last one.
* Note that we count a timed checkpoint in stats only when this
* occurs without an external request, but we set the CAUSE_TIME flag
* bit even if there is also an external request.
* checkpoint , , checkpoint.
* , , ,
* ; , CAUSE_TIME .
*/
now = (pg_time_t) time(NULL);//
elapsed_secs = now - last_checkpoint_time;//
if (elapsed_secs >= CheckPointTimeout)
{
//
if (!do_checkpoint)
BgWriterStats.m_timed_checkpoints++;// checkpoint ,
do_checkpoint = true;//
flags |= CHECKPOINT_CAUSE_TIME;//
}
/*
* Do a checkpoint if requested.
* checkpoint
*/
if (do_checkpoint)
{
bool ckpt_performed = false;//
bool do_restartpoint;
/*
* Check if we should perform a checkpoint or a restartpoint. As a
* side-effect, RecoveryInProgress() initializes TimeLineID if
* it's not set yet.
* checkpoint restartpoint.
* , TimeLineID, RecoveryInProgress() TimeLineID
*/
do_restartpoint = RecoveryInProgress();
/*
* Atomically fetch the request flags to figure out what kind of a
* checkpoint we should perform, and increase the started-counter
* to acknowledge that we've started a new checkpoint.
* , checkpoint , checkpoint.
*/
SpinLockAcquire(&CheckpointerShmem->ckpt_lck);
flags |= CheckpointerShmem->ckpt_flags;
CheckpointerShmem->ckpt_flags = 0;
CheckpointerShmem->ckpt_started++;
SpinLockRelease(&CheckpointerShmem->ckpt_lck);
/*
* The end-of-recovery checkpoint is a real checkpoint that's
* performed while we're still in recovery.
* end-of-recovery checkpoint checkpoint.
*/
if (flags & CHECKPOINT_END_OF_RECOVERY)
do_restartpoint = false;
/*
* We will warn if (a) too soon since last checkpoint (whatever
* caused it) and (b) somebody set the CHECKPOINT_CAUSE_XLOG flag
* since the last checkpoint start. Note in particular that this
* implementation will not generate warnings caused by
* CheckPointTimeout ckpt_lck);
CheckpointerShmem->ckpt_done = CheckpointerShmem->ckpt_started;
SpinLockRelease(&CheckpointerShmem->ckpt_lck);
if (ckpt_performed)
{
// checkpoint
/*
* Note we record the checkpoint start time not end time as
* last_checkpoint_time. This is so that time-driven
* checkpoints happen at a predictable spacing.
* checkpoint last_checkpoint_time.
* , 。
*/
last_checkpoint_time = now;
}
else
{
//
/*
* We were not able to perform the restartpoint (checkpoints
* throw an ERROR in case of error). Most likely because we
* have not received any new checkpoint WAL records since the
* last restartpoint. Try again in 15 s.
* restartpoint( checkpoint , ).
* restartpoint checkpoint WAL .
* 15s .
*/
last_checkpoint_time = now - CheckPointTimeout + 15;
}
ckpt_active = false;
}
/* Check for archive_timeout and switch xlog files if necessary. */
// , archive_timeout xlog .
CheckArchiveTimeout();
/*
* Send off activity statistics to the stats collector. (The reason
* why we re-use bgwriter-related code for this is that the bgwriter
* and checkpointer used to be just one process. It's probably not
* worth the trouble to split the stats support into two independent
* stats message types.)
* .
*/
pgstat_send_bgwriter();
/*
* Sleep until we are signaled or it's time for another checkpoint or
* xlog file switch.
* , checkpoint xlog .
*/
//
now = (pg_time_t) time(NULL);
elapsed_secs = now - last_checkpoint_time;
if (elapsed_secs >= CheckPointTimeout)
continue; /* no sleep for us ... */
cur_timeout = CheckPointTimeout - elapsed_secs;
if (XLogArchiveTimeout > 0 && !RecoveryInProgress())
{
elapsed_secs = now - last_xlog_switch_time;
if (elapsed_secs >= XLogArchiveTimeout)
continue; /* no sleep for us ... */
cur_timeout = Min(cur_timeout, XLogArchiveTimeout - elapsed_secs);//
}
(void) WaitLatch(MyLatch,
WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
cur_timeout * 1000L /* convert to ms */ ,
WAIT_EVENT_CHECKPOINTER_MAIN);//
}
}
/*
* Unix-like signal handler installation
* Unix
* Only called on main thread, no sync required
* , sync .
*/
pqsigfunc
pqsignal(int signum, pqsigfunc handler)
{
pqsigfunc prevfunc;//
if (signum >= PG_SIGNAL_COUNT || signum info_lck);
recptr = XLogCtl->LogwrtRqst.Write;//
SpinLockRelease(&XLogCtl->info_lck);
return recptr;
}
3. 추적 분석
데이터 시트 만 들 기, 데이터 삽입, checkpoint 실행
testdb=# drop table t_wal_ckpt;
DROP TABLE
testdb=# create table t_wal_ckpt(c1 int not null,c2 varchar(40),c3 varchar(40));
CREATE TABLE
testdb=# insert into t_wal_ckpt(c1,c2,c3) values(1,'C2-1','C3-1');
INSERT 0 1
testdb=#
testdb=# checkpoint; --> checkpoint
데 이 터 를 업데이트 하고 체크 포 인 트 를 실행 합 니 다.
testdb=# update t_wal_ckpt set c2 = 'C2#'||substr(c2,4,40);
UPDATE 1
testdb=# checkpoint;
gdb 시작, 신호 제어 설정
(gdb) handle SIGINT print nostop pass
SIGINT is used by the debugger.
Are you sure you want to change it? (y or n) y
Signal Stop Print Pass to program Description
SIGINT No Yes Yes Interrupt
(gdb)
(gdb) b checkpointer.c:441
Breakpoint 1 at 0x815197: file checkpointer.c, line 441.
(gdb) c
Continuing.
Program received signal SIGINT, Interrupt.
Breakpoint 1, CheckpointerMain () at checkpointer.c:441
441 flags |= CheckpointerShmem->ckpt_flags;
(gdb)
공유 메모리 정보 보기 CheckpointerShmem
(gdb) p *CheckpointerShmem
$1 = {checkpointer_pid = 1650, ckpt_lck = 1 '\001', ckpt_started = 2, ckpt_done = 2, ckpt_failed = 0, ckpt_flags = 44,
num_backend_writes = 0, num_backend_fsync = 0, num_requests = 0, max_requests = 65536, requests = 0x7f2cdda07b28}
(gdb)
관련 정보 설정 CheckpointerShmem
441 flags |= CheckpointerShmem->ckpt_flags;
(gdb) n
442 CheckpointerShmem->ckpt_flags = 0;
(gdb)
443 CheckpointerShmem->ckpt_started++;
(gdb)
444 SpinLockRelease(&CheckpointerShmem->ckpt_lck);
(gdb)
450 if (flags & CHECKPOINT_END_OF_RECOVERY)
(gdb)
460 if (!do_restartpoint &&
(gdb)
461 (flags & CHECKPOINT_CAUSE_XLOG) &&
(gdb)
460 if (!do_restartpoint &&
checkpointer 프로 세 스 가 checkpoint 과정 에서 사용 할 개인 변 수 를 초기 화 합 니 다. 그 중 ckptstart_recptr 는 삽입 점, 즉 Redo point, 5521180544 를 16 진법 으로 0 x1 49168780 으로 전환 합 니 다.
(gdb)
474 ckpt_active = true;
(gdb)
475 if (do_restartpoint)
(gdb)
478 ckpt_start_recptr = GetInsertRecPtr();
(gdb) p XLogCtl->LogwrtRqst
$1 = {Write = 5521180544, Flush = 5521180544}
(gdb) n
479 ckpt_start_time = now;
(gdb) p ckpt_start_recptr
$2 = 5521180544
(gdb) n
480 ckpt_cached_elapsed = 0;
(gdb)
485 if (!do_restartpoint)
(gdb)
checkpoint. OK 를 실행 합 니 다!
(gdb)
487 CreateCheckPoint(flags);
(gdb)
488 ckpt_performed = true;
(gdb)
자원 을 닫 고 공유 메모리 의 정 보 를 설정 합 니 다.
497 smgrcloseall();
(gdb)
502 SpinLockAcquire(&CheckpointerShmem->ckpt_lck);
(gdb)
503 CheckpointerShmem->ckpt_done = CheckpointerShmem->ckpt_started;
(gdb)
504 SpinLockRelease(&CheckpointerShmem->ckpt_lck);
(gdb)
506 if (ckpt_performed)
(gdb) p CheckpointerShmem
$3 = (CheckpointerShmemStruct *) 0x7fcecc063b00
(gdb) p *CheckpointerShmem
$4 = {checkpointer_pid = 1697, ckpt_lck = 0 '\000', ckpt_started = 1, ckpt_done = 1, ckpt_failed = 0, ckpt_flags = 0,
num_backend_writes = 0, num_backend_fsync = 0, num_requests = 0, max_requests = 65536, requests = 0x7fcecc063b28}
(gdb)
checkpoint 요청 이 삭제 되 었 습 니 다.
(gdb) p CheckpointerShmem->requests[0]
$5 = {rnode = {spcNode = 0, dbNode = 0, relNode = 0}, forknum = MAIN_FORKNUM, segno = 0}
필요 할 때 archive 검사timeout 및 xlog 파일 을 전환 합 니 다. 신 호 를 받 거나 새로운 checkpoint 나 xlog 파일 전환 을 시작 해 야 할 때 까지 휴면 합 니 다.
(gdb) n
513 last_checkpoint_time = now;
(gdb)
526 ckpt_active = false;
(gdb)
530 CheckArchiveTimeout();
(gdb)
539 pgstat_send_bgwriter();
(gdb)
545 now = (pg_time_t) time(NULL);
(gdb)
546 elapsed_secs = now - last_checkpoint_time;
(gdb)
547 if (elapsed_secs >= CheckPointTimeout)
(gdb) p elapsed_secs
$7 = 1044
(gdb) p CheckPointTimeout
$8 = 900
(gdb) n
548 continue; /* no sleep for us ... */
시간 초과, 새로운 checkpoint 실행
(gdb)
569 }
(gdb)
352 bool do_checkpoint = false;
(gdb)
353 int flags = 0;
(gdb) n
360 ResetLatch(MyLatch);
(gdb)
365 AbsorbFsyncRequests();
(gdb)
367 if (got_SIGHUP)
(gdb)
385 if (checkpoint_requested)
(gdb)
391 if (shutdown_requested)
(gdb)
410 now = (pg_time_t) time(NULL);
(gdb)
411 elapsed_secs = now - last_checkpoint_time;
(gdb)
412 if (elapsed_secs >= CheckPointTimeout)
(gdb) p elapsed_secs
$9 = 1131
(gdb) n
414 if (!do_checkpoint)
(gdb)
415 BgWriterStats.m_timed_checkpoints++;
(gdb)
416 do_checkpoint = true;
(gdb)
417 flags |= CHECKPOINT_CAUSE_TIME;
(gdb)
423 if (do_checkpoint)
(gdb)
425 bool ckpt_performed = false;
(gdb)
433 do_restartpoint = RecoveryInProgress();
(gdb)
440 SpinLockAcquire(&CheckpointerShmem->ckpt_lck);
(gdb)
Breakpoint 1, CheckpointerMain () at checkpointer.c:441
441 flags |= CheckpointerShmem->ckpt_flags;
(gdb)
442 CheckpointerShmem->ckpt_flags = 0;
(gdb)
443 CheckpointerShmem->ckpt_started++;
(gdb) c
Continuing.
DONE!
Create CheckPoint 함수 다음 절 소개
참고 자료
checkpointer.c
"ITPUB 블 로그" 에서 왔 습 니 다. 링크:http://blog.itpub.net/6906/viewspace-2374762/전재 가 필요 하 다 면 출처 를 밝 혀 주 십시오. 그렇지 않 으 면 법 적 책임 을 추궁 할 것 입 니 다.
다음으로 전송:http://blog.itpub.net/6906/viewspace-2374762/
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.