/* * Get the next, maximum buffer space for reading. * * Returns NULL when the current file has been completely read. */ uint8 *BufferedReadGetMaxBuffer( BufferedRead *bufferedRead, int32 *nextBufferLen) { Assert(bufferedRead != NULL); Assert(bufferedRead->file >= 0); Assert(nextBufferLen != NULL); return BufferedReadGetNextBuffer( bufferedRead, bufferedRead->maxBufferLen, nextBufferLen, true); }
/* * Skip zero padding to next page boundary, if necessary. * * This function is called when the file system block we are scanning has * no more valid data but instead is padded with zero's from the position * we are currently in until the end of the block. The function will skip * to the end of block if skipLen is -1 or skip skipLen bytes otherwise. */ static bool AppendOnlyStorageRead_PositionToNextBlock(AppendOnlyStorageRead *storageRead, int64 *headerOffsetInFile, uint8 **header, int32 *blockLimitLen) { int32 availableLen; int i; int64 fileRemainderLen; Assert(storageRead != NULL); Assert(header != NULL); /* * Peek ahead just enough so we can see the Append-Only storage header. * * However, we need to honor the file-system page boundaries here since we * do not let the length information cross the boundary. */ AppendOnlyStorageRead_DoSkipPadding(storageRead, storageRead->minimumHeaderLen); *headerOffsetInFile = BufferedReadNextBufferPosition(&storageRead->bufferedRead); *header = BufferedReadGetNextBuffer(&storageRead->bufferedRead, storageRead->minimumHeaderLen, &availableLen); if (*header == NULL) { /* done reading the file */ return false; } storageRead->bufferCount++; if (availableLen != storageRead->minimumHeaderLen) ereport(ERROR, (errcode(ERRCODE_GP_INTERNAL_ERROR), errmsg("Expected %d bytes and got %d bytes in table %s (segment file '%s', header offset in file = " INT64_FORMAT ", bufferCount " INT64_FORMAT ")\n", storageRead->minimumHeaderLen, availableLen, storageRead->relationName, storageRead->segmentFileName, *headerOffsetInFile, storageRead->bufferCount))); /* * First check for zero padded page remainder. */ i = 0; while (true) { if ((*header)[i] != 0) break; i++; if (i >= storageRead->minimumHeaderLen) { /* * Skip over zero padding caused when the append command left a * partially full page. */ AppendOnlyStorageRead_DoSkipPadding(storageRead, -1 /* means till end of * page */ ); /* * Now try to get the peek data from the new page. */ *headerOffsetInFile = BufferedReadNextBufferPosition(&storageRead->bufferedRead); *header = BufferedReadGetNextBuffer(&storageRead->bufferedRead, storageRead->minimumHeaderLen, &availableLen); if (*header == NULL) { /* done reading the file */ return false; } if (availableLen != storageRead->minimumHeaderLen) ereport(ERROR, (errcode(ERRCODE_GP_INTERNAL_ERROR), errmsg("Expected %d bytes and found %d bytes in table %s (segment file '%s', header offset in file = " INT64_FORMAT ", bufferCount " INT64_FORMAT ")", storageRead->minimumHeaderLen, availableLen, storageRead->relationName, storageRead->segmentFileName, *headerOffsetInFile, storageRead->bufferCount))); break; } } /* * Determine the maximum boundary of the block. UNDONE: When we have a * block directory, we will tighten the limit down. */ fileRemainderLen = storageRead->bufferedRead.fileLen - *headerOffsetInFile; if (storageRead->maxBufferLen > fileRemainderLen) *blockLimitLen = (int32) fileRemainderLen; else *blockLimitLen = storageRead->maxBufferLen; return true; }
/* * Skip zero padding to next page boundary, if necessary. * * This function is called when the file system block we are scanning has * no more valid data but instead is padded with zero's from the position * we are currently in until the end of the block. The function will skip * to the end of block if skipLen is -1 or skip skipLen bytes otherwise. */ static void AppendOnlyStorageRead_DoSkipPadding(AppendOnlyStorageRead *storageRead, int32 skipLen) { int64 nextReadPosition; int64 nextBoundaryPosition; int32 safeWriteRemainder; bool doSkip; uint8 *buffer; int32 availableLen; int32 safewrite = storageRead->storageAttributes.safeFSWriteSize; /* early exit if no pad used */ if (safewrite == 0) return; nextReadPosition = BufferedReadNextBufferPosition(&storageRead->bufferedRead); nextBoundaryPosition = ((nextReadPosition + safewrite - 1) / safewrite) * safewrite; safeWriteRemainder = (int32) (nextBoundaryPosition - nextReadPosition); if (safeWriteRemainder <= 0) doSkip = false; else if (skipLen == -1) { /* * Skip to end of page. */ doSkip = true; skipLen = safeWriteRemainder; } else doSkip = (safeWriteRemainder < skipLen); if (doSkip) { /* * Read through the remainder. */ buffer = BufferedReadGetNextBuffer(&storageRead->bufferedRead, safeWriteRemainder, &availableLen); /* * Since our file EOF should always be a multiple of the file-system * page, we do not expect a short read here. */ if (buffer == NULL) availableLen = 0; if (buffer == NULL || safeWriteRemainder != availableLen) { ereport(ERROR, (errcode(ERRCODE_GP_INTERNAL_ERROR), errmsg("Unexpected end of file. Expected to read %d bytes after position " INT64_FORMAT " but found %d bytes (bufferCount " INT64_FORMAT ")\n", safeWriteRemainder, nextReadPosition, availableLen, storageRead->bufferCount))); } /* * UNDONE: For verification purposes, we should verify the * remainder is all zeroes. */ elogif(Debug_appendonly_print_scan, LOG, "Append-only scan skipping zero padded remainder for table '%s' (nextReadPosition = " INT64_FORMAT ", safeWriteRemainder = %d)", storageRead->relationName, nextReadPosition, safeWriteRemainder); } }