diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 1999-10-16 19:49:28 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 1999-10-16 19:49:28 +0000 |
commit | 957146dcec9cc2fb31220c26c51802623df04e5e (patch) | |
tree | af3b58f8d85bf796a5ff810df45accf27de042af /src/backend/storage/file/buffile.c | |
parent | 357231e68e5a9333904b1ebc6ac82410a4a21f0e (diff) |
Second phase of psort reconstruction project: add bookkeeping logic to
recycle storage within sort temp file on a block-by-block basis. This
reduces peak disk usage to essentially just the volume of data being
sorted, whereas it had been about 4x the data volume before.
Diffstat (limited to 'src/backend/storage/file/buffile.c')
-rw-r--r-- | src/backend/storage/file/buffile.c | 234 |
1 files changed, 108 insertions, 126 deletions
diff --git a/src/backend/storage/file/buffile.c b/src/backend/storage/file/buffile.c index cd7da900b4f..452e3a187df 100644 --- a/src/backend/storage/file/buffile.c +++ b/src/backend/storage/file/buffile.c @@ -6,7 +6,7 @@ * Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/storage/file/buffile.c,v 1.1 1999/10/13 15:02:29 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/storage/file/buffile.c,v 1.2 1999/10/16 19:49:26 tgl Exp $ * * NOTES: * @@ -27,10 +27,7 @@ * * BufFile also supports temporary files that exceed the OS file size limit * (by opening multiple fd.c temporary files). This is an essential feature - * for sorts and hashjoins on large amounts of data. It is possible to have - * more than one BufFile reading/writing the same temp file, although the - * caller is responsible for avoiding ill effects from buffer overlap when - * this is done. + * for sorts and hashjoins on large amounts of data. *------------------------------------------------------------------------- */ @@ -48,33 +45,24 @@ #define MAX_PHYSICAL_FILESIZE (RELSEG_SIZE * BLCKSZ) /* - * To handle multiple BufFiles on a single logical temp file, we use this - * data structure representing a logical file (which can be made up of - * multiple physical files to get around the OS file size limit). + * This data structure represents a buffered file that consists of one or + * more physical files (each accessed through a virtual file descriptor + * managed by fd.c). */ -typedef struct LogicalFile +struct BufFile { - int refCount; /* number of BufFiles using me */ - bool isTemp; /* can only add files if this is TRUE */ int numFiles; /* number of physical files in set */ /* all files except the last have length exactly MAX_PHYSICAL_FILESIZE */ - File *files; /* palloc'd array with numFiles entries */ long *offsets; /* palloc'd array with numFiles entries */ /* offsets[i] is the current seek position of files[i]. We use this * to avoid making redundant FileSeek calls. */ -} LogicalFile; -/* - * A single file buffer looks like this. - */ -struct BufFile -{ - LogicalFile *logFile; /* the underlying LogicalFile */ + bool isTemp; /* can only add files if this is TRUE */ bool dirty; /* does buffer need to be written? */ /* - * "current pos" is position of start of buffer within LogicalFile. + * "current pos" is position of start of buffer within the logical file. * Position as seen by user of BufFile is (curFile, curOffset + pos). */ int curFile; /* file index (0..n) part of current pos */ @@ -84,30 +72,33 @@ struct BufFile char buffer[BLCKSZ]; }; -static LogicalFile *makeLogicalFile(File firstfile); -static void extendLogicalFile(LogicalFile *file); -static void deleteLogicalFile(LogicalFile *file); +static BufFile *makeBufFile(File firstfile); +static void extendBufFile(BufFile *file); static void BufFileLoadBuffer(BufFile *file); static void BufFileDumpBuffer(BufFile *file); static int BufFileFlush(BufFile *file); /* - * Create a LogicalFile with one component file and refcount 1. + * Create a BufFile given the first underlying physical file. * NOTE: caller must set isTemp true if appropriate. */ -static LogicalFile * -makeLogicalFile(File firstfile) +static BufFile * +makeBufFile(File firstfile) { - LogicalFile *file = (LogicalFile *) palloc(sizeof(LogicalFile)); + BufFile *file = (BufFile *) palloc(sizeof(BufFile)); - file->refCount = 1; - file->isTemp = false; file->numFiles = 1; file->files = (File *) palloc(sizeof(File)); file->files[0] = firstfile; file->offsets = (long *) palloc(sizeof(long)); file->offsets[0] = 0L; + file->isTemp = false; + file->dirty = false; + file->curFile = 0; + file->curOffset = 0L; + file->pos = 0; + file->nbytes = 0; return file; } @@ -116,7 +107,7 @@ makeLogicalFile(File firstfile) * Add another component temp file. */ static void -extendLogicalFile(LogicalFile *file) +extendBufFile(BufFile *file) { File pfile; @@ -134,21 +125,6 @@ extendLogicalFile(LogicalFile *file) } /* - * Close and delete a LogicalFile when its refCount has gone to zero. - */ -static void -deleteLogicalFile(LogicalFile *file) -{ - int i; - - for (i = 0; i < file->numFiles; i++) - FileClose(file->files[i]); - pfree(file->files); - pfree(file->offsets); - pfree(file); -} - -/* * Create a BufFile for a new temporary file (which will expand to become * multiple temporary files if more than MAX_PHYSICAL_FILESIZE bytes are * written to it). @@ -156,24 +132,16 @@ deleteLogicalFile(LogicalFile *file) BufFile * BufFileCreateTemp(void) { - BufFile *bfile = (BufFile *) palloc(sizeof(BufFile)); + BufFile *file; File pfile; - LogicalFile *lfile; pfile = OpenTemporaryFile(); Assert(pfile >= 0); - lfile = makeLogicalFile(pfile); - lfile->isTemp = true; - - bfile->logFile = lfile; - bfile->dirty = false; - bfile->curFile = 0; - bfile->curOffset = 0L; - bfile->pos = 0; - bfile->nbytes = 0; + file = makeBufFile(pfile); + file->isTemp = true; - return bfile; + return file; } /* @@ -186,42 +154,7 @@ BufFileCreateTemp(void) BufFile * BufFileCreate(File file) { - BufFile *bfile = (BufFile *) palloc(sizeof(BufFile)); - LogicalFile *lfile; - - lfile = makeLogicalFile(file); - - bfile->logFile = lfile; - bfile->dirty = false; - bfile->curFile = 0; - bfile->curOffset = 0L; - bfile->pos = 0; - bfile->nbytes = 0; - - return bfile; -} - -/* - * Create an additional BufFile accessing the same underlying file as an - * existing BufFile. This is useful for having multiple read/write access - * positions in a single temporary file. Note the caller is responsible - * for avoiding trouble due to overlapping buffer positions! (Caller may - * assume that buffer size is BLCKSZ...) - */ -BufFile * -BufFileReaccess(BufFile *file) -{ - BufFile *bfile = (BufFile *) palloc(sizeof(BufFile)); - - bfile->logFile = file->logFile; - bfile->logFile->refCount++; - bfile->dirty = false; - bfile->curFile = 0; - bfile->curOffset = 0L; - bfile->pos = 0; - bfile->nbytes = 0; - - return bfile; + return makeBufFile(file); } /* @@ -232,16 +165,21 @@ BufFileReaccess(BufFile *file) void BufFileClose(BufFile *file) { + int i; + /* flush any unwritten data */ BufFileFlush(file); - /* close the underlying (with delete if it's a temp file) */ - if (--(file->logFile->refCount) <= 0) - deleteLogicalFile(file->logFile); + /* close the underlying file(s) (with delete if it's a temp file) */ + for (i = 0; i < file->numFiles; i++) + FileClose(file->files[i]); /* release the buffer space */ + pfree(file->files); + pfree(file->offsets); pfree(file); } -/* BufFileLoadBuffer +/* + * BufFileLoadBuffer * * Load some data into buffer, if possible, starting from curOffset. * At call, must have dirty = false, pos and nbytes = 0. @@ -250,7 +188,6 @@ BufFileClose(BufFile *file) static void BufFileLoadBuffer(BufFile *file) { - LogicalFile *lfile = file->logFile; File thisfile; /* @@ -261,30 +198,33 @@ BufFileLoadBuffer(BufFile *file) * MAX_PHYSICAL_FILESIZE. */ if (file->curOffset >= MAX_PHYSICAL_FILESIZE && - file->curFile+1 < lfile->numFiles) + file->curFile+1 < file->numFiles) { file->curFile++; file->curOffset = 0L; } - thisfile = lfile->files[file->curFile]; /* - * May need to reposition physical file, if more than one BufFile - * is using it. + * May need to reposition physical file. */ - if (file->curOffset != lfile->offsets[file->curFile]) + thisfile = file->files[file->curFile]; + if (file->curOffset != file->offsets[file->curFile]) { if (FileSeek(thisfile, file->curOffset, SEEK_SET) != file->curOffset) return; /* seek failed, read nothing */ - lfile->offsets[file->curFile] = file->curOffset; + file->offsets[file->curFile] = file->curOffset; } + /* + * Read whatever we can get, up to a full bufferload. + */ file->nbytes = FileRead(thisfile, file->buffer, sizeof(file->buffer)); if (file->nbytes < 0) file->nbytes = 0; - lfile->offsets[file->curFile] += file->nbytes; + file->offsets[file->curFile] += file->nbytes; /* we choose not to advance curOffset here */ } -/* BufFileDumpBuffer +/* + * BufFileDumpBuffer * * Dump buffer contents starting at curOffset. * At call, should have dirty = true, nbytes > 0. @@ -293,7 +233,6 @@ BufFileLoadBuffer(BufFile *file) static void BufFileDumpBuffer(BufFile *file) { - LogicalFile *lfile = file->logFile; int wpos = 0; int bytestowrite; File thisfile; @@ -307,10 +246,10 @@ BufFileDumpBuffer(BufFile *file) /* * Advance to next component file if necessary and possible. */ - if (file->curOffset >= MAX_PHYSICAL_FILESIZE && lfile->isTemp) + if (file->curOffset >= MAX_PHYSICAL_FILESIZE && file->isTemp) { - while (file->curFile+1 >= lfile->numFiles) - extendLogicalFile(lfile); + while (file->curFile+1 >= file->numFiles) + extendBufFile(file); file->curFile++; file->curOffset = 0L; } @@ -319,28 +258,27 @@ BufFileDumpBuffer(BufFile *file) * to write as much as asked... */ bytestowrite = file->nbytes - wpos; - if (lfile->isTemp) + if (file->isTemp) { long availbytes = MAX_PHYSICAL_FILESIZE - file->curOffset; if ((long) bytestowrite > availbytes) bytestowrite = (int) availbytes; } - thisfile = lfile->files[file->curFile]; /* - * May need to reposition physical file, if more than one BufFile - * is using it. + * May need to reposition physical file. */ - if (file->curOffset != lfile->offsets[file->curFile]) + thisfile = file->files[file->curFile]; + if (file->curOffset != file->offsets[file->curFile]) { if (FileSeek(thisfile, file->curOffset, SEEK_SET) != file->curOffset) return; /* seek failed, give up */ - lfile->offsets[file->curFile] = file->curOffset; + file->offsets[file->curFile] = file->curOffset; } bytestowrite = FileWrite(thisfile, file->buffer, bytestowrite); if (bytestowrite <= 0) return; /* failed to write */ - lfile->offsets[file->curFile] += bytestowrite; + file->offsets[file->curFile] += bytestowrite; file->curOffset += bytestowrite; wpos += bytestowrite; } @@ -363,7 +301,8 @@ BufFileDumpBuffer(BufFile *file) file->nbytes = 0; } -/* BufFileRead +/* + * BufFileRead * * Like fread() except we assume 1-byte element size. */ @@ -409,7 +348,8 @@ BufFileRead(BufFile *file, void *ptr, size_t size) return nread; } -/* BufFileWrite +/* + * BufFileWrite * * Like fwrite() except we assume 1-byte element size. */ @@ -458,7 +398,8 @@ BufFileWrite(BufFile *file, void *ptr, size_t size) return nwritten; } -/* BufFileFlush +/* + * BufFileFlush * * Like fflush() */ @@ -475,9 +416,15 @@ BufFileFlush(BufFile *file) return 0; } -/* BufFileSeek +/* + * BufFileSeek * - * Like fseek(). Result is 0 if OK, EOF if not. + * Like fseek(), except that target position needs two values in order to + * work when logical filesize exceeds maximum value representable by long. + * We do not support relative seeks across more than LONG_MAX, however. + * + * Result is 0 if OK, EOF if not. Logical position is not moved if an + * impossible seek is attempted. */ int BufFileSeek(BufFile *file, int fileno, long offset, int whence) @@ -487,7 +434,7 @@ BufFileSeek(BufFile *file, int fileno, long offset, int whence) switch (whence) { case SEEK_SET: - if (fileno < 0 || fileno >= file->logFile->numFiles || + if (fileno < 0 || fileno >= file->numFiles || offset < 0) return EOF; newFile = fileno; @@ -516,11 +463,11 @@ BufFileSeek(BufFile *file, int fileno, long offset, int whence) return EOF; newOffset += MAX_PHYSICAL_FILESIZE; } - if (file->logFile->isTemp) + if (file->isTemp) { while (newOffset > MAX_PHYSICAL_FILESIZE) { - if (++newFile >= file->logFile->numFiles) + if (++newFile >= file->numFiles) return EOF; newOffset -= MAX_PHYSICAL_FILESIZE; } @@ -548,9 +495,44 @@ BufFileSeek(BufFile *file, int fileno, long offset, int whence) return 0; } -extern void +void BufFileTell(BufFile *file, int *fileno, long *offset) { *fileno = file->curFile; *offset = file->curOffset + file->pos; } + +/* + * BufFileSeekBlock --- block-oriented seek + * + * Performs absolute seek to the start of the n'th BLCKSZ-sized block of + * the file. Note that users of this interface will fail if their files + * exceed BLCKSZ * LONG_MAX bytes, but that is quite a lot; we don't work + * with tables bigger than that, either... + * + * Result is 0 if OK, EOF if not. Logical position is not moved if an + * impossible seek is attempted. + */ +int +BufFileSeekBlock(BufFile *file, long blknum) +{ + return BufFileSeek(file, + (int) (blknum / RELSEG_SIZE), + (blknum % RELSEG_SIZE) * BLCKSZ, + SEEK_SET); +} + +/* + * BufFileTellBlock --- block-oriented tell + * + * Any fractional part of a block in the current seek position is ignored. + */ +long +BufFileTellBlock(BufFile *file) +{ + long blknum; + + blknum = (file->curOffset + file->pos) / BLCKSZ; + blknum += file->curFile * RELSEG_SIZE; + return blknum; +} |