/* It might also be the newest item decoded, decode_queue_tail. */ if (state->decode_queue_tail == record)
state->decode_queue_tail = NULL;
/* Release the space. */ if (unlikely(record->oversized))
{ /* It's not in the decode buffer, so free it to release space. */
pfree(record);
} else
{ /* It must be the head (oldest) record in the decode buffer. */
Assert(state->decode_buffer_head == (char *) record);
/* *Weneedtoupdateheadtopointtothenextrecordthatisinthe *decodebuffer,ifany,beingcarefultoskipoversizedones *(they'renotinthedecodebuffer).
*/
record = record->next; while (unlikely(record && record->oversized))
record = record->next;
if (record)
{ /* Adjust head to release space up to the next record. */
state->decode_buffer_head = (char *) record;
} else
{ /* *Otherwisewemightaswelljustresetheadandtailtothe *startofthebufferspace,becausewe'reempty.Thismeans *we'llkeepoverwritingthesamepieceofmemoryifwe'renot *doinganyprefetching.
*/
state->decode_buffer_head = state->decode_buffer;
state->decode_buffer_tail = state->decode_buffer;
}
}
return next_lsn;
}
/* *AttempttoreadanXLOGrecord. * *XLogBeginRead()orXLogFindNextRecord()andthenXLogReadAhead()mustbe *calledbeforethefirstcalltoXLogNextRecord().Thisfunctionsreturns *recordsanderrorsthatwereputintoaninternalqueuebyXLogReadAhead(). * *Onsuccess,arecordisreturned. * *Thereturnedrecord(or*errormsg)pointstoaninternalbufferthat's *validuntilthenextcalltoXLogNextRecord.
*/
DecodedXLogRecord *
XLogNextRecord(XLogReaderState *state, char **errormsg)
{ /* Release the last record returned by XLogNextRecord(). */
XLogReleasePreviousRecord(state);
if (state->decode_queue_head == NULL)
{
*errormsg = NULL; if (state->errormsg_deferred)
{ if (state->errormsg_buf[0] != '\0')
*errormsg = state->errormsg_buf;
state->errormsg_deferred = false;
}
/* Allocate a circular decode buffer if we don't have one already. */ if (unlikely(state->decode_buffer == NULL))
{ if (state->decode_buffer_size == 0)
state->decode_buffer_size = DEFAULT_DECODE_BUFFER_SIZE;
state->decode_buffer = palloc(state->decode_buffer_size);
state->decode_buffer_head = state->decode_buffer;
state->decode_buffer_tail = state->decode_buffer;
state->free_decode_buffer = true;
}
/* Try to allocate space in the circular decode buffer. */ if (state->decode_buffer_tail >= state->decode_buffer_head)
{ /* Empty, or tail is to the right of head. */ if (required_space <=
state->decode_buffer_size -
(state->decode_buffer_tail - state->decode_buffer))
{ /*- *Thereisspacebetweentailandend. * *+-----+--------------------+-----+ *||////////////////////|here!| *+-----+--------------------+-----+ *^^ *|| *ht
*/
decoded = (DecodedXLogRecord *) state->decode_buffer_tail;
decoded->oversized = false; return decoded;
} elseif (required_space <
state->decode_buffer_head - state->decode_buffer)
{ /*- *Thereisspacebetweenstartandhead. * *+-----+--------------------+-----+ *|here!|////////////////////| | *+-----+--------------------+-----+ *^^ *|| *ht
*/
decoded = (DecodedXLogRecord *) state->decode_buffer;
decoded->oversized = false; return decoded;
}
} else
{ /* Tail is to the left of head. */ if (required_space <
state->decode_buffer_head - state->decode_buffer_tail)
{ /*- *Thereisspacebetweentailandhead. * *+-----+--------------------+-----+ *|/////|here! |/////| *+-----+--------------------+-----+ *^^ *|| *th
*/
decoded = (DecodedXLogRecord *) state->decode_buffer_tail;
decoded->oversized = false; return decoded;
}
}
/* Not enough space in the decode buffer. Are we allowed to allocate? */ if (allow_oversized)
{
decoded = palloc(required_space);
decoded->oversized = true; return decoded;
}
/* *Ifthewholerecordheaderisonthispage,validateitimmediately. *Otherwisedojustabasicsanitycheckonxl_tot_len,andvalidatethe *restoftheheaderafterreadingitfromthenextpage.Thexl_tot_len *checkisnecessaryheretoensurethatweenterthe"Needtoreassemble *record"codepathbelow;otherwisewemightfailtoapply *ValidXLogRecordHeaderatall.
*/ if (targetRecOff <= XLOG_BLCKSZ - SizeOfXLogRecord)
{ if (!ValidXLogRecordHeader(state, RecPtr, state->DecodeRecPtr, record,
randAccess)) goto err;
gotheader = true;
} else
{ /* There may be no next page if it's too small. */ if (total_len < SizeOfXLogRecord)
{
report_invalid_record(state, "invalid record length at %X/%X: expected at least %u, got %u",
LSN_FORMAT_ARGS(RecPtr),
(uint32) SizeOfXLogRecord, total_len); goto err;
} /* We'll validate the header once we have the next page. */
gotheader = false;
}
/* Copy the first fragment of the record from the first page. */
memcpy(state->readRecordBuf,
state->readBuf + RecPtr % XLOG_BLCKSZ, len);
buffer = state->readRecordBuf + len;
gotlen = len;
do
{ /* Calculate pointer to beginning of next page */
targetPagePtr += XLOG_BLCKSZ;
/* Check that the continuation on next page looks valid */ if (!(pageHeader->xlp_info & XLP_FIRST_IS_CONTRECORD))
{
report_invalid_record(state, "there is no contrecord flag at %X/%X",
LSN_FORMAT_ARGS(RecPtr)); goto err;
}
/* Wait for the next page to become available */
readOff = ReadPageInternal(state, targetPagePtr,
Min(total_len - gotlen + SizeOfXLogShortPHD,
XLOG_BLCKSZ)); if (readOff == XLREAD_WOULDBLOCK) return XLREAD_WOULDBLOCK; elseif (readOff < 0) goto err;
/* Append the continuation from this page to the buffer */
pageHeaderSize = XLogPageHeaderSize(pageHeader);
if (readOff < pageHeaderSize)
readOff = ReadPageInternal(state, targetPagePtr,
pageHeaderSize);
Assert(pageHeaderSize <= readOff);
contdata = (char *) state->readBuf + pageHeaderSize;
len = XLOG_BLCKSZ - pageHeaderSize; if (pageHeader->xlp_rem_len < len)
len = pageHeader->xlp_rem_len;
/* If we just reassembled the record header, validate it. */ if (!gotheader)
{
record = (XLogRecord *) state->readRecordBuf; if (!ValidXLogRecordHeader(state, RecPtr, state->DecodeRecPtr,
record, randAccess)) goto err;
gotheader = true;
}
record = (XLogRecord *) state->readRecordBuf; if (!ValidXLogRecord(state, record, RecPtr)) goto err;
pageHeaderSize = XLogPageHeaderSize((XLogPageHeader) state->readBuf);
state->DecodeRecPtr = RecPtr;
state->NextRecPtr = targetPagePtr + pageHeaderSize
+ MAXALIGN(pageHeader->xlp_rem_len);
} else
{ /* Wait for the record data to become available */
readOff = ReadPageInternal(state, targetPagePtr,
Min(targetRecOff + total_len, XLOG_BLCKSZ)); if (readOff == XLREAD_WOULDBLOCK) return XLREAD_WOULDBLOCK; elseif (readOff < 0) goto err;
/* Record does not cross a page boundary */ if (!ValidXLogRecord(state, record, RecPtr)) goto err;
state->NextRecPtr = RecPtr + MAXALIGN(total_len);
state->DecodeRecPtr = RecPtr;
}
/* *Specialprocessingifit'sanXLOGSWITCHrecord
*/ if (record->xl_rmid == RM_XLOG_ID &&
(record->xl_info & ~XLR_INFO_MASK) == XLOG_SWITCH)
{ /* Pretend it extends to end of segment */
state->NextRecPtr += state->segcxt.ws_segsize - 1;
state->NextRecPtr -= XLogSegmentOffset(state->NextRecPtr, state->segcxt.ws_segsize);
}
/* *IfwegotherewithoutaDecodedXLogRecord,itmeansweneededto *validatetotal_lenbeforetrustingit,butbynowwe'vedonethat.
*/ if (decoded == NULL)
{
Assert(!nonblocking);
decoded = XLogReadRecordAlloc(state,
total_len, true/* allow_oversized */ ); /* allocation should always happen under allow_oversized */
Assert(decoded != NULL);
}
if (DecodeXLogRecord(state, decoded, record, RecPtr, &errormsg))
{ /* Record the location of the next record. */
decoded->next_lsn = state->NextRecPtr;
/* *Ifit'sinthedecodebuffer,markthedecodebufferspaceas *occupied.
*/ if (!decoded->oversized)
{ /* The new decode buffer head must be MAXALIGNed. */
Assert(decoded->size == MAXALIGN(decoded->size)); if ((char *) decoded == state->decode_buffer)
state->decode_buffer_tail = state->decode_buffer + decoded->size; else
state->decode_buffer_tail += decoded->size;
}
/* Insert it into the queue of decoded records. */
Assert(state->decode_queue_tail != decoded); if (state->decode_queue_tail)
state->decode_queue_tail->next = decoded;
state->decode_queue_tail = decoded; if (!state->decode_queue_head)
state->decode_queue_head = decoded; return XLREAD_SUCCESS;
}
/* check whether we have all the requested data already */ if (targetSegNo == state->seg.ws_segno &&
targetPageOff == state->segoff && reqLen <= state->readLen) return state->readLen;
/* Calculate the CRC */
INIT_CRC32C(crc);
COMP_CRC32C(crc, ((char *) record) + SizeOfXLogRecord, record->xl_tot_len - SizeOfXLogRecord); /* include the record header last */
COMP_CRC32C(crc, (char *) record, offsetof(XLogRecord, xl_crc));
FIN_CRC32C(crc);
if (!EQ_CRC32C(record->xl_crc, crc))
{
report_invalid_record(state, "incorrect resource manager data checksum in record at %X/%X",
LSN_FORMAT_ARGS(recptr)); returnfalse;
}
/* hmm, first page of file doesn't have a long header? */
report_invalid_record(state, "invalid info bits %04X in WAL segment %s, LSN %X/%X, offset %u",
hdr->xlp_info,
fname,
LSN_FORMAT_ARGS(recptr),
offset); returnfalse;
}
/* *weknownowthattmpRecPtrisanaddresspointingtoavalidXLogRecord *becauseeitherwe'reatthefirstrecordafterthebeginningofapage *orwejustjumpedovertheremainingdataofacontinuation.
*/
XLogBeginRead(state, tmpRecPtr); while (XLogReadRecord(state, &errormsg) != NULL)
{ /* past the record we've found, break out */ if (RecPtr <= state->ReadRecPtr)
{ /* Rewind the reader to the beginning of the last record. */
found = state->ReadRecPtr;
XLogBeginRead(state, found); return found;
}
}
/* This shouldn't happen -- indicates a bug in segment_open */
Assert(state->seg.ws_file >= 0);
/* Update the current segment info. */
state->seg.ws_tli = tli;
state->seg.ws_segno = nextSegNo;
}
/* How many bytes are within this segment? */ if (nbytes > (state->segcxt.ws_segsize - startoff))
segbytes = state->segcxt.ws_segsize - startoff; else
segbytes = nbytes;
/* Account for the fixed size part of the decoded record struct. */
size += offsetof(DecodedXLogRecord, blocks[0]); /* Account for the flexible blocks array of maximum possible size. */
size += sizeof(DecodedBkpBlock) * (XLR_MAX_BLOCK_ID + 1); /* Account for all the raw main and block data. */
size += xl_tot_len; /* We might insert padding before main_data. */
size += (MAXIMUM_ALIGNOF - 1); /* We might insert padding before each block's data. */
size += (MAXIMUM_ALIGNOF - 1) * (XLR_MAX_BLOCK_ID + 1); /* We might insert padding at the end. */
size += (MAXIMUM_ALIGNOF - 1);
/* Decode the headers */
datatotal = 0; while (remaining > datatotal)
{
COPY_HEADER_FIELD(&block_id, sizeof(uint8));
if (block_id == XLR_BLOCK_ID_DATA_SHORT)
{ /* XLogRecordDataHeaderShort */
uint8 main_data_len;
COPY_HEADER_FIELD(&main_data_len, sizeof(uint8));
decoded->main_data_len = main_data_len;
datatotal += main_data_len; break; /* by convention, the main data fragment is
* always last */
} elseif (block_id == XLR_BLOCK_ID_DATA_LONG)
{ /* XLogRecordDataHeaderLong */
uint32 main_data_len;
COPY_HEADER_FIELD(&main_data_len, sizeof(uint32));
decoded->main_data_len = main_data_len;
datatotal += main_data_len; break; /* by convention, the main data fragment is
* always last */
} elseif (block_id == XLR_BLOCK_ID_ORIGIN)
{
COPY_HEADER_FIELD(&decoded->record_origin, sizeof(RepOriginId));
} elseif (block_id == XLR_BLOCK_ID_TOPLEVEL_XID)
{
COPY_HEADER_FIELD(&decoded->toplevel_xid, sizeof(TransactionId));
} elseif (block_id <= XLR_MAX_BLOCK_ID)
{ /* XLogRecordBlockHeader */
DecodedBkpBlock *blk;
uint8 fork_flags;
/* mark any intervening block IDs as not in use */ for (int i = decoded->max_block_id + 1; i < block_id; ++i)
decoded->blocks[i].in_use = false;
if (block_id <= decoded->max_block_id)
{
report_invalid_record(state, "out-of-order block_id %u at %X/%X",
block_id,
LSN_FORMAT_ARGS(state->ReadRecPtr)); goto err;
}
decoded->max_block_id = block_id;
COPY_HEADER_FIELD(&blk->data_len, sizeof(uint16)); /* cross-check that the HAS_DATA flag is set iff data_length > 0 */ if (blk->has_data && blk->data_len == 0)
{
report_invalid_record(state, "BKPBLOCK_HAS_DATA set, but no data included at %X/%X",
LSN_FORMAT_ARGS(state->ReadRecPtr)); goto err;
} if (!blk->has_data && blk->data_len != 0)
{
report_invalid_record(state, "BKPBLOCK_HAS_DATA not set, but data length is %u at %X/%X",
(unsignedint) blk->data_len,
LSN_FORMAT_ARGS(state->ReadRecPtr)); goto err;
}
datatotal += blk->data_len;
if (blk->has_image)
{
COPY_HEADER_FIELD(&blk->bimg_len, sizeof(uint16));
COPY_HEADER_FIELD(&blk->hole_offset, sizeof(uint16));
COPY_HEADER_FIELD(&blk->bimg_info, sizeof(uint8));
/* block data first */ for (block_id = 0; block_id <= decoded->max_block_id; block_id++)
{
DecodedBkpBlock *blk = &decoded->blocks[block_id];
if (!blk->in_use) continue;
Assert(blk->has_image || !blk->apply_image);
if (blk->has_image)
{ /* no need to align image */
blk->bkp_image = out;
memcpy(out, ptr, blk->bimg_len);
ptr += blk->bimg_len;
out += blk->bimg_len;
} if (blk->has_data)
{
out = (char *) MAXALIGN(out);
blk->data = out;
memcpy(blk->data, ptr, blk->data_len);
ptr += blk->data_len;
out += blk->data_len;
}
}
/* and finally, the main data */ if (decoded->main_data_len > 0)
{
out = (char *) MAXALIGN(out);
decoded->main_data = out;
memcpy(decoded->main_data, ptr, decoded->main_data_len);
ptr += decoded->main_data_len;
out += decoded->main_data_len;
}
/* Report the actual size we used. */
decoded->size = MAXALIGN(out - (char *) decoded);
Assert(DecodeXLogRecordRequiredSpace(record->xl_tot_len) >=
decoded->size);
returntrue;
shortdata_err:
report_invalid_record(state, "record with invalid length at %X/%X",
LSN_FORMAT_ARGS(state->ReadRecPtr));
err:
*errormsg = state->errormsg_buf;
returnfalse;
}
/* *Returnsinformationabouttheblockthatablockreferencerefersto. * *ThisislikeXLogRecGetBlockTagExtended,exceptthattheblockreference *mustexistandthere'snoaccesstoprefetch_buffer.
*/ void
XLogRecGetBlockTag(XLogReaderState *record, uint8 block_id,
RelFileLocator *rlocator, ForkNumber *forknum,
BlockNumber *blknum)
{ if (!XLogRecGetBlockTagExtended(record, block_id, rlocator, forknum,
blknum, NULL))
{ #ifndef FRONTEND
elog(ERROR, "could not locate backup block with ID %d in WAL record",
block_id); #else
pg_fatal("could not locate backup block with ID %d in WAL record",
block_id); #endif
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.