/* * mdextend() -- Add a block to the specified relation. * * The semantics are basically the same as mdwrite(): write at the * specified position. However, we are expecting to extend the * relation (ie, blocknum is the current EOF), and so in case of * failure we clean up by truncating. * * This routine returns true or false, with errno set as appropriate. * * Note: this routine used to call mdnblocks() to get the block position * to write at, but that's pretty silly since the caller needs to know where * the block will be written, and accordingly must have done mdnblocks() * already. Might as well pass in the position and save a seek. */ bool mdextend(SMgrRelation reln, BlockNumber blocknum, char *buffer, bool isTemp) { long seekpos; int nbytes; MdfdVec *v; v = _mdfd_getseg(reln, blocknum, false); #ifndef LET_OS_MANAGE_FILESIZE seekpos = (long) (BLCKSZ * (blocknum % ((BlockNumber) RELSEG_SIZE))); Assert(seekpos < BLCKSZ * RELSEG_SIZE); #else seekpos = (long) (BLCKSZ * (blocknum)); #endif /* * Note: because caller obtained blocknum by calling _mdnblocks, which did * a seek(SEEK_END), this seek is often redundant and will be optimized * away by fd.c. It's not redundant, however, if there is a partial page * at the end of the file. In that case we want to try to overwrite the * partial page with a full page. It's also not redundant if bufmgr.c had * to dump another buffer of the same file to make room for the new page's * buffer. */ if (FileSeek(v->mdfd_vfd, seekpos, SEEK_SET) != seekpos) return false; if ((nbytes = FileWrite(v->mdfd_vfd, buffer, BLCKSZ)) != BLCKSZ) { if (nbytes > 0) { int save_errno = errno; /* Remove the partially-written page */ FileTruncate(v->mdfd_vfd, seekpos); FileSeek(v->mdfd_vfd, seekpos, SEEK_SET); errno = save_errno; } return false; } if (!isTemp) { if (!register_dirty_segment(reln, v)) return false; } #ifndef LET_OS_MANAGE_FILESIZE Assert(_mdnblocks(v->mdfd_vfd, BLCKSZ) <= ((BlockNumber) RELSEG_SIZE)); #endif return true; }
bool MirroredBufferPool_Truncate( MirroredBufferPoolOpen *open, /* The open struct. */ int64 position) /* The position to cutoff the data. */ { int primaryError; primaryError = 0; /* * For Buffer Pool managed, we are normally not session oriented like Append-Only. * * Figure out mirroring each time... */ MirroredBufferPool_RecheckMirrorAccess(open); if (StorageManagerMirrorMode_SendToMirror(open->mirrorMode) && !open->mirrorDataLossOccurred) { if (FileRepPrimary_MirrorTruncate( FileRep_GetRelationIdentifier( open->mirrorFilespaceLocation, open->relFileNode, open->segmentFileNum), FileRepRelationTypeBufferPool, position) != 0) { if (Debug_filerep_print) ereport(LOG, (errmsg("could not sent file truncate request to mirror "), FileRep_ReportRelationPath( open->mirrorFilespaceLocation, open->relFileNode, open->segmentFileNum))); } open->mirrorDataLossOccurred = FileRepPrimary_IsMirrorDataLossOccurred(); } if (StorageManagerMirrorMode_DoPrimaryWork(open->mirrorMode) && ! FileRepResyncWorker_IsResyncRequest()) { errno = 0; if (FileTruncate(open->primaryFile, position) < 0) primaryError = errno; } errno = primaryError; return (primaryError == 0); }
void PhoneGapFile::actionTruncate(JSONMessage& message) { String callbackID = message.getParam("PhoneGapCallBackId"); String fullPath = message.getArgsField("fileName"); int size = message.getArgsFieldInt("size"); int result = FileTruncate(fullPath, size); if (result < 0) { callFileError(callbackID, FILEERROR_NOT_FOUND_ERR); return; } // Send back the result, the new length of the file. char lengthBuf[32]; sprintf(lengthBuf, "%i", result); callSuccess(callbackID, lengthBuf); }
/* * mdtruncate() -- Truncate relation to specified number of blocks. */ void mdtruncate(SMgrRelation reln, ForkNumber forknum, BlockNumber nblocks, bool isTemp) { MdfdVec *v; BlockNumber curnblk; BlockNumber priorblocks; /* * NOTE: mdnblocks makes sure we have opened all active segments, so that * truncation loop will get them all! */ curnblk = mdnblocks(reln, forknum); if (nblocks > curnblk) { /* Bogus request ... but no complaint if InRecovery */ if (InRecovery) return; ereport(ERROR, (errmsg("could not truncate file \"%s\" to %u blocks: it's only %u blocks now", relpath(reln->smgr_rnode, forknum), nblocks, curnblk))); } if (nblocks == curnblk) return; /* no work */ v = mdopen(reln, forknum, EXTENSION_FAIL); priorblocks = 0; while (v != NULL) { MdfdVec *ov = v; if (priorblocks > nblocks) { /* * This segment is no longer active (and has already been unlinked * from the mdfd_chain). We truncate the file, but do not delete * it, for reasons explained in the header comments. */ if (FileTruncate(v->mdfd_vfd, 0) < 0) ereport(ERROR, (errcode_for_file_access(), errmsg("could not truncate file \"%s\": %m", FilePathName(v->mdfd_vfd)))); if (!isTemp) register_dirty_segment(reln, forknum, v); v = v->mdfd_chain; Assert(ov != reln->md_fd[forknum]); /* we never drop the 1st * segment */ pfree(ov); } else if (priorblocks + ((BlockNumber) RELSEG_SIZE) > nblocks) { /* * This is the last segment we want to keep. Truncate the file to * the right length, and clear chain link that points to any * remaining segments (which we shall zap). NOTE: if nblocks is * exactly a multiple K of RELSEG_SIZE, we will truncate the K+1st * segment to 0 length but keep it. This adheres to the invariant * given in the header comments. */ BlockNumber lastsegblocks = nblocks - priorblocks; if (FileTruncate(v->mdfd_vfd, (off_t) lastsegblocks * BLCKSZ) < 0) ereport(ERROR, (errcode_for_file_access(), errmsg("could not truncate file \"%s\" to %u blocks: %m", FilePathName(v->mdfd_vfd), nblocks))); if (!isTemp) register_dirty_segment(reln, forknum, v); v = v->mdfd_chain; ov->mdfd_chain = NULL; } else { /* * We still need this segment and 0 or more blocks beyond it, so * nothing to do here. */ v = v->mdfd_chain; } priorblocks += RELSEG_SIZE; } }
/* * Opens the next segment file to write. The file must already exist. * This routine is responsible for seeking to the proper write location * given the logical EOF. * * @filePathName: The name of the segment file to open. * @logicalEof: The last committed write transaction's EOF * value to use as the end of the segment file. * @parquet_file The file handler of segment file */ static void OpenSegmentFile( MirroredAppendOnlyOpen *mirroredOpen, char *filePathName, int64 logicalEof, RelFileNode *relFileNode, int32 segmentFileNum, char *relname, File *parquet_file, File *parquet_file_previous, CompactProtocol **protocol_read, TupleDesc tableAttrs, ParquetMetadata *parquetMetadata, int64 *fileLen, int64 *fileLen_uncompressed, int *previous_rowgroupcnt) { int primaryError; File file; int64 seekResult; Assert(filePathName != NULL); bool metadataExist = false; /* * Open the file for metadata reading. */ MirroredAppendOnly_OpenReadWrite(mirroredOpen, relFileNode, segmentFileNum, relname, logicalEof, true, &primaryError); if (primaryError != 0) ereport(ERROR, (errcode_for_file_access(), errmsg("file open error when opening file " "'%s' for relation '%s': %s", filePathName, relname, strerror(primaryError)))); *parquet_file_previous = mirroredOpen->primaryFile; int64 fileSize = FileSeek(*parquet_file_previous, 0, SEEK_END); if (fileSize < 0){ ereport(ERROR, (errcode_for_file_access(), errmsg("file seek error in file '%s' for relation " "'%s'", filePathName, relname))); } if (logicalEof > fileSize) { ereport(ERROR, (errcode(ERRCODE_GP_INTERNAL_ERROR), errmsg("logical eof exceeds file size in file '%s' for relation '%s'", filePathName, relname))); } /*read parquet footer, get metadata information before rowgroup metadata*/ metadataExist = readParquetFooter(*parquet_file_previous, parquetMetadata, protocol_read, logicalEof, filePathName); *previous_rowgroupcnt = (*parquetMetadata)->blockCount; /* * Open the file for writing. */ MirroredAppendOnly_OpenReadWrite(mirroredOpen, relFileNode, segmentFileNum, relname, logicalEof, false, &primaryError); if (primaryError != 0) ereport(ERROR, (errcode_for_file_access(), errmsg("file open error when opening file '%s' " "for relation '%s': %s", filePathName, relname, strerror(primaryError)))); file = mirroredOpen->primaryFile; seekResult = FileNonVirtualTell(file); if (seekResult != logicalEof) { /* previous transaction is aborted truncate file*/ if (FileTruncate(file, logicalEof)) { MirroredAppendOnly_Close(mirroredOpen); ereport(ERROR, (errcode_for_file_access(), errmsg("file truncate error in file '%s' for relation " "'%s' to position " INT64_FORMAT ": %s", filePathName, relname, logicalEof, strerror(errno)))); } } *parquet_file = file; /*if metadata not exist, should initialize the metadata, and write out file header*/ if (metadataExist == false) { /* init parquet metadata information, init schema information using table attributes, * and may get existing information from data file*/ initparquetMetadata(*parquetMetadata, tableAttrs, *parquet_file); /*should judge whether file already exists, if a new file, should write header out*/ writeParquetHeader(*parquet_file, filePathName, fileLen, fileLen_uncompressed); } else { if (!checkAndSyncMetadata(*parquetMetadata, tableAttrs)) { ereport(ERROR, (errcode(ERRCODE_GP_INTERNAL_ERROR), errmsg("parquet storage write file's metadata incompatible " "with table's schema for relation '%s'.", relname))); } } }
/* * mdtruncate() -- Truncate relation to specified number of blocks. * * Returns # of blocks or InvalidBlockNumber on error. */ BlockNumber mdtruncate(SMgrRelation reln, BlockNumber nblocks, bool isTemp) { MdfdVec *v; BlockNumber curnblk; #ifndef LET_OS_MANAGE_FILESIZE BlockNumber priorblocks; #endif /* * NOTE: mdnblocks makes sure we have opened all existing segments, so * that truncate/delete loop will get them all! */ curnblk = mdnblocks(reln); if (curnblk == InvalidBlockNumber) return InvalidBlockNumber; /* mdnblocks failed */ if (nblocks > curnblk) return InvalidBlockNumber; /* bogus request */ if (nblocks == curnblk) return nblocks; /* no work */ v = mdopen(reln, false); #ifndef LET_OS_MANAGE_FILESIZE priorblocks = 0; while (v != NULL) { MdfdVec *ov = v; if (priorblocks > nblocks) { /* * This segment is no longer wanted at all (and has already been * unlinked from the mdfd_chain). We truncate the file before * deleting it because if other backends are holding the file * open, the unlink will fail on some platforms. Better a * zero-size file gets left around than a big file... */ FileTruncate(v->mdfd_vfd, 0); FileUnlink(v->mdfd_vfd); v = v->mdfd_chain; Assert(ov != reln->md_fd); /* we never drop the 1st segment */ pfree(ov); } else if (priorblocks + ((BlockNumber) RELSEG_SIZE) > nblocks) { /* * This is the last segment we want to keep. Truncate the file to * the right length, and clear chain link that points to any * remaining segments (which we shall zap). NOTE: if nblocks is * exactly a multiple K of RELSEG_SIZE, we will truncate the K+1st * segment to 0 length but keep it. This is mainly so that the * right thing happens if nblocks==0. */ BlockNumber lastsegblocks = nblocks - priorblocks; if (FileTruncate(v->mdfd_vfd, lastsegblocks * BLCKSZ) < 0) return InvalidBlockNumber; if (!isTemp) { if (!register_dirty_segment(reln, v)) return InvalidBlockNumber; } v = v->mdfd_chain; ov->mdfd_chain = NULL; } else { /* * We still need this segment and 0 or more blocks beyond it, so * nothing to do here. */ v = v->mdfd_chain; } priorblocks += RELSEG_SIZE; } #else if (FileTruncate(v->mdfd_vfd, nblocks * BLCKSZ) < 0) return InvalidBlockNumber; if (!isTemp) { if (!register_dirty_segment(reln, v)) return InvalidBlockNumber; } #endif return nblocks; }
/* * mdtruncate() -- Truncate relation to specified number of blocks. * * Returns # of blocks or InvalidBlockNumber on error. */ BlockNumber mdtruncate(SMgrRelation reln, BlockNumber nblocks, bool isTemp) { MdfdVec *v; BlockNumber curnblk; #ifndef LET_OS_MANAGE_FILESIZE BlockNumber priorblocks; #endif /* * NOTE: mdnblocks makes sure we have opened all active segments, so * that truncation loop will get them all! */ curnblk = mdnblocks(reln); if (curnblk == InvalidBlockNumber) return InvalidBlockNumber; /* mdnblocks failed */ if (nblocks > curnblk) return InvalidBlockNumber; /* bogus request */ if (nblocks == curnblk) return nblocks; /* no work */ v = mdopen(reln, false); #ifndef LET_OS_MANAGE_FILESIZE priorblocks = 0; while (v != NULL) { MdfdVec *ov = v; if (priorblocks > nblocks) { /* * This segment is no longer active (and has already been * unlinked from the mdfd_chain). We truncate the file, but do * not delete it, for reasons explained in the header comments. */ if (FileTruncate(v->mdfd_vfd, 0) < 0) return InvalidBlockNumber; if (!isTemp) { if (!register_dirty_segment(reln, v)) return InvalidBlockNumber; } v = v->mdfd_chain; Assert(ov != reln->md_fd); /* we never drop the 1st segment */ pfree(ov); } else if (priorblocks + ((BlockNumber) RELSEG_SIZE) > nblocks) { /* * This is the last segment we want to keep. Truncate the file to * the right length, and clear chain link that points to any * remaining segments (which we shall zap). NOTE: if nblocks is * exactly a multiple K of RELSEG_SIZE, we will truncate the K+1st * segment to 0 length but keep it. This adheres to the invariant * given in the header comments. */ BlockNumber lastsegblocks = nblocks - priorblocks; if (FileTruncate(v->mdfd_vfd, lastsegblocks * BLCKSZ) < 0) return InvalidBlockNumber; if (!isTemp) { if (!register_dirty_segment(reln, v)) return InvalidBlockNumber; } v = v->mdfd_chain; ov->mdfd_chain = NULL; } else { /* * We still need this segment and 0 or more blocks beyond it, so * nothing to do here. */ v = v->mdfd_chain; } priorblocks += RELSEG_SIZE; } #else if (FileTruncate(v->mdfd_vfd, nblocks * BLCKSZ) < 0) return InvalidBlockNumber; if (!isTemp) { if (!register_dirty_segment(reln, v)) return InvalidBlockNumber; } #endif return nblocks; }