PostgreSQL Source Code  git master
logtape.c File Reference
#include "postgres.h"
#include "storage/buffile.h"
#include "utils/builtins.h"
#include "utils/logtape.h"
#include "utils/memdebug.h"
#include "utils/memutils.h"
Include dependency graph for logtape.c:

Go to the source code of this file.

Data Structures

struct  TapeBlockTrailer
 
struct  LogicalTape
 
struct  LogicalTapeSet
 

Macros

#define TapeBlockPayloadSize   (BLCKSZ - sizeof(TapeBlockTrailer))
 
#define TapeBlockGetTrailer(buf)   ((TapeBlockTrailer *) ((char *) buf + TapeBlockPayloadSize))
 
#define TapeBlockIsLast(buf)   (TapeBlockGetTrailer(buf)->next < 0)
 
#define TapeBlockGetNBytes(buf)
 
#define TapeBlockSetNBytes(buf, nbytes)   (TapeBlockGetTrailer(buf)->next = -(nbytes))
 

Typedefs

typedef struct TapeBlockTrailer TapeBlockTrailer
 
typedef struct LogicalTape LogicalTape
 

Functions

static void ltsWriteBlock (LogicalTapeSet *lts, long blocknum, void *buffer)
 
static void ltsReadBlock (LogicalTapeSet *lts, long blocknum, void *buffer)
 
static long ltsGetFreeBlock (LogicalTapeSet *lts)
 
static void ltsReleaseBlock (LogicalTapeSet *lts, long blocknum)
 
static void ltsConcatWorkerTapes (LogicalTapeSet *lts, TapeShare *shared, SharedFileSet *fileset)
 
static bool ltsReadFillBuffer (LogicalTapeSet *lts, LogicalTape *lt)
 
static int freeBlocks_cmp (const void *a, const void *b)
 
LogicalTapeSetLogicalTapeSetCreate (int ntapes, TapeShare *shared, SharedFileSet *fileset, int worker)
 
void LogicalTapeSetClose (LogicalTapeSet *lts)
 
void LogicalTapeSetForgetFreeSpace (LogicalTapeSet *lts)
 
void LogicalTapeWrite (LogicalTapeSet *lts, int tapenum, void *ptr, size_t size)
 
void LogicalTapeRewindForRead (LogicalTapeSet *lts, int tapenum, size_t buffer_size)
 
void LogicalTapeRewindForWrite (LogicalTapeSet *lts, int tapenum)
 
size_t LogicalTapeRead (LogicalTapeSet *lts, int tapenum, void *ptr, size_t size)
 
void LogicalTapeFreeze (LogicalTapeSet *lts, int tapenum, TapeShare *share)
 
size_t LogicalTapeBackspace (LogicalTapeSet *lts, int tapenum, size_t size)
 
void LogicalTapeSeek (LogicalTapeSet *lts, int tapenum, long blocknum, int offset)
 
void LogicalTapeTell (LogicalTapeSet *lts, int tapenum, long *blocknum, int *offset)
 
long LogicalTapeSetBlocks (LogicalTapeSet *lts)
 

Macro Definition Documentation

◆ TapeBlockGetNBytes

#define TapeBlockGetNBytes (   buf)
Value:
#define TapeBlockIsLast(buf)
Definition: logtape.c:110
#define TapeBlockPayloadSize
Definition: logtape.c:106
static char * buf
Definition: pg_test_fsync.c:67
#define TapeBlockGetTrailer(buf)
Definition: logtape.c:107

Definition at line 111 of file logtape.c.

Referenced by LogicalTapeFreeze(), and ltsReadFillBuffer().

◆ TapeBlockGetTrailer

#define TapeBlockGetTrailer (   buf)    ((TapeBlockTrailer *) ((char *) buf + TapeBlockPayloadSize))

◆ TapeBlockIsLast

#define TapeBlockIsLast (   buf)    (TapeBlockGetTrailer(buf)->next < 0)

Definition at line 110 of file logtape.c.

Referenced by LogicalTapeFreeze(), and ltsReadFillBuffer().

◆ TapeBlockPayloadSize

#define TapeBlockPayloadSize   (BLCKSZ - sizeof(TapeBlockTrailer))

Definition at line 106 of file logtape.c.

Referenced by LogicalTapeBackspace(), LogicalTapeSeek(), and LogicalTapeWrite().

◆ TapeBlockSetNBytes

#define TapeBlockSetNBytes (   buf,
  nbytes 
)    (TapeBlockGetTrailer(buf)->next = -(nbytes))

Definition at line 114 of file logtape.c.

Referenced by LogicalTapeFreeze(), and LogicalTapeRewindForRead().

Typedef Documentation

◆ LogicalTape

typedef struct LogicalTape LogicalTape

◆ TapeBlockTrailer

Function Documentation

◆ freeBlocks_cmp()

static int freeBlocks_cmp ( const void *  a,
const void *  b 
)
static

Definition at line 328 of file logtape.c.

Referenced by ltsGetFreeBlock().

329 {
330  long ablk = *((const long *) a);
331  long bblk = *((const long *) b);
332 
333  /* can't just subtract because long might be wider than int */
334  if (ablk < bblk)
335  return 1;
336  if (ablk > bblk)
337  return -1;
338  return 0;
339 }

◆ LogicalTapeBackspace()

size_t LogicalTapeBackspace ( LogicalTapeSet lts,
int  tapenum,
size_t  size 
)

Definition at line 960 of file logtape.c.

References Assert, LogicalTape::buffer, LogicalTape::buffer_size, LogicalTape::curBlockNumber, elog, ERROR, LogicalTape::firstBlockNumber, LogicalTape::frozen, ltsReadBlock(), LogicalTape::nbytes, LogicalTape::nextBlockNumber, LogicalTape::pos, TapeBlockTrailer::prev, TapeBlockGetTrailer, TapeBlockPayloadSize, and LogicalTapeSet::tapes.

Referenced by tuplesort_gettuple_common().

961 {
962  LogicalTape *lt;
963  size_t seekpos = 0;
964 
965  Assert(tapenum >= 0 && tapenum < lts->nTapes);
966  lt = &lts->tapes[tapenum];
967  Assert(lt->frozen);
968  Assert(lt->buffer_size == BLCKSZ);
969 
970  /*
971  * Easy case for seek within current block.
972  */
973  if (size <= (size_t) lt->pos)
974  {
975  lt->pos -= (int) size;
976  return size;
977  }
978 
979  /*
980  * Not-so-easy case, have to walk back the chain of blocks. This
981  * implementation would be pretty inefficient for long seeks, but we
982  * really aren't doing that (a seek over one tuple is typical).
983  */
984  seekpos = (size_t) lt->pos; /* part within this block */
985  while (size > seekpos)
986  {
987  long prev = TapeBlockGetTrailer(lt->buffer)->prev;
988 
989  if (prev == -1L)
990  {
991  /* Tried to back up beyond the beginning of tape. */
992  if (lt->curBlockNumber != lt->firstBlockNumber)
993  elog(ERROR, "unexpected end of tape");
994  lt->pos = 0;
995  return seekpos;
996  }
997 
998  ltsReadBlock(lts, prev, (void *) lt->buffer);
999 
1000  if (TapeBlockGetTrailer(lt->buffer)->next != lt->curBlockNumber)
1001  elog(ERROR, "broken tape, next of block %ld is %ld, expected %ld",
1002  prev,
1003  TapeBlockGetTrailer(lt->buffer)->next,
1004  lt->curBlockNumber);
1005 
1007  lt->curBlockNumber = prev;
1008  lt->nextBlockNumber = TapeBlockGetTrailer(lt->buffer)->next;
1009 
1010  seekpos += TapeBlockPayloadSize;
1011  }
1012 
1013  /*
1014  * 'seekpos' can now be greater than 'size', because it points to the
1015  * beginning the target block. The difference is the position within the
1016  * page.
1017  */
1018  lt->pos = seekpos - size;
1019  return size;
1020 }
LogicalTape tapes[FLEXIBLE_ARRAY_MEMBER]
Definition: logtape.c:205
#define TapeBlockPayloadSize
Definition: logtape.c:106
bool frozen
Definition: logtape.c:131
long nextBlockNumber
Definition: logtape.c:147
#define ERROR
Definition: elog.h:43
int nbytes
Definition: logtape.c:157
long firstBlockNumber
Definition: logtape.c:145
long curBlockNumber
Definition: logtape.c:146
#define Assert(condition)
Definition: c.h:739
char * buffer
Definition: logtape.c:153
#define elog(elevel,...)
Definition: elog.h:228
int buffer_size
Definition: logtape.c:154
#define TapeBlockGetTrailer(buf)
Definition: logtape.c:107
static void ltsReadBlock(LogicalTapeSet *lts, long blocknum, void *buffer)
Definition: logtape.c:270

◆ LogicalTapeFreeze()

void LogicalTapeFreeze ( LogicalTapeSet lts,
int  tapenum,
TapeShare share 
)

Definition at line 876 of file logtape.c.

References Assert, LogicalTape::buffer, LogicalTape::buffer_size, BufFileExportShared(), LogicalTape::curBlockNumber, LogicalTape::dirty, TapeShare::firstblocknumber, LogicalTape::firstBlockNumber, LogicalTape::frozen, ltsReadBlock(), ltsWriteBlock(), LogicalTape::nbytes, LogicalTape::nextBlockNumber, LogicalTape::offsetBlockNumber, palloc(), LogicalTapeSet::pfile, pfree(), LogicalTape::pos, TapeBlockGetNBytes, TapeBlockGetTrailer, TapeBlockIsLast, TapeBlockSetNBytes, LogicalTapeSet::tapes, VALGRIND_MAKE_MEM_DEFINED, and LogicalTape::writing.

Referenced by mergeruns(), and worker_freeze_result_tape().

877 {
878  LogicalTape *lt;
879 
880  Assert(tapenum >= 0 && tapenum < lts->nTapes);
881  lt = &lts->tapes[tapenum];
882  Assert(lt->writing);
883  Assert(lt->offsetBlockNumber == 0L);
884 
885  /*
886  * Completion of a write phase. Flush last partial data block, and rewind
887  * for nondestructive read.
888  */
889  if (lt->dirty)
890  {
891  /*
892  * As long as we've filled the buffer at least once, its contents are
893  * entirely defined from valgrind's point of view, even though
894  * contents beyond the current end point may be stale. But it's
895  * possible - at least in the case of a parallel sort - to sort such
896  * small amount of data that we do not fill the buffer even once. Tell
897  * valgrind that its contents are defined, so it doesn't bleat.
898  */
900  lt->buffer_size - lt->nbytes);
901 
902  TapeBlockSetNBytes(lt->buffer, lt->nbytes);
903  ltsWriteBlock(lts, lt->curBlockNumber, (void *) lt->buffer);
904  lt->writing = false;
905  }
906  lt->writing = false;
907  lt->frozen = true;
908 
909  /*
910  * The seek and backspace functions assume a single block read buffer.
911  * That's OK with current usage. A larger buffer is helpful to make the
912  * read pattern of the backing file look more sequential to the OS, when
913  * we're reading from multiple tapes. But at the end of a sort, when a
914  * tape is frozen, we only read from a single tape anyway.
915  */
916  if (!lt->buffer || lt->buffer_size != BLCKSZ)
917  {
918  if (lt->buffer)
919  pfree(lt->buffer);
920  lt->buffer = palloc(BLCKSZ);
921  lt->buffer_size = BLCKSZ;
922  }
923 
924  /* Read the first block, or reset if tape is empty */
926  lt->pos = 0;
927  lt->nbytes = 0;
928 
929  if (lt->firstBlockNumber == -1L)
930  lt->nextBlockNumber = -1L;
931  ltsReadBlock(lts, lt->curBlockNumber, (void *) lt->buffer);
932  if (TapeBlockIsLast(lt->buffer))
933  lt->nextBlockNumber = -1L;
934  else
935  lt->nextBlockNumber = TapeBlockGetTrailer(lt->buffer)->next;
936  lt->nbytes = TapeBlockGetNBytes(lt->buffer);
937 
938  /* Handle extra steps when caller is to share its tapeset */
939  if (share)
940  {
942  share->firstblocknumber = lt->firstBlockNumber;
943  }
944 }
LogicalTape tapes[FLEXIBLE_ARRAY_MEMBER]
Definition: logtape.c:205
#define VALGRIND_MAKE_MEM_DEFINED(addr, size)
Definition: memdebug.h:26
#define TapeBlockIsLast(buf)
Definition: logtape.c:110
long offsetBlockNumber
Definition: logtape.c:148
BufFile * pfile
Definition: logtape.c:168
long firstblocknumber
Definition: logtape.h:50
bool frozen
Definition: logtape.c:131
long nextBlockNumber
Definition: logtape.c:147
bool writing
Definition: logtape.c:130
bool dirty
Definition: logtape.c:132
void pfree(void *pointer)
Definition: mcxt.c:1056
int nbytes
Definition: logtape.c:157
long firstBlockNumber
Definition: logtape.c:145
#define TapeBlockSetNBytes(buf, nbytes)
Definition: logtape.c:114
long curBlockNumber
Definition: logtape.c:146
#define Assert(condition)
Definition: c.h:739
void BufFileExportShared(BufFile *file)
Definition: buffile.c:373
#define TapeBlockGetNBytes(buf)
Definition: logtape.c:111
char * buffer
Definition: logtape.c:153
void * palloc(Size size)
Definition: mcxt.c:949
int buffer_size
Definition: logtape.c:154
static void ltsWriteBlock(LogicalTapeSet *lts, long blocknum, void *buffer)
Definition: logtape.c:222
#define TapeBlockGetTrailer(buf)
Definition: logtape.c:107
static void ltsReadBlock(LogicalTapeSet *lts, long blocknum, void *buffer)
Definition: logtape.c:270

◆ LogicalTapeRead()

size_t LogicalTapeRead ( LogicalTapeSet lts,
int  tapenum,
void *  ptr,
size_t  size 
)

Definition at line 822 of file logtape.c.

References Assert, LogicalTape::buffer, ltsReadFillBuffer(), LogicalTape::nbytes, LogicalTape::pos, LogicalTapeSet::tapes, and LogicalTape::writing.

Referenced by getlen().

824 {
825  LogicalTape *lt;
826  size_t nread = 0;
827  size_t nthistime;
828 
829  Assert(tapenum >= 0 && tapenum < lts->nTapes);
830  lt = &lts->tapes[tapenum];
831  Assert(!lt->writing);
832 
833  while (size > 0)
834  {
835  if (lt->pos >= lt->nbytes)
836  {
837  /* Try to load more data into buffer. */
838  if (!ltsReadFillBuffer(lts, lt))
839  break; /* EOF */
840  }
841 
842  nthistime = lt->nbytes - lt->pos;
843  if (nthistime > size)
844  nthistime = size;
845  Assert(nthistime > 0);
846 
847  memcpy(ptr, lt->buffer + lt->pos, nthistime);
848 
849  lt->pos += nthistime;
850  ptr = (void *) ((char *) ptr + nthistime);
851  size -= nthistime;
852  nread += nthistime;
853  }
854 
855  return nread;
856 }
LogicalTape tapes[FLEXIBLE_ARRAY_MEMBER]
Definition: logtape.c:205
static bool ltsReadFillBuffer(LogicalTapeSet *lts, LogicalTape *lt)
Definition: logtape.c:286
bool writing
Definition: logtape.c:130
int nbytes
Definition: logtape.c:157
#define Assert(condition)
Definition: c.h:739
char * buffer
Definition: logtape.c:153

◆ LogicalTapeRewindForRead()

void LogicalTapeRewindForRead ( LogicalTapeSet lts,
int  tapenum,
size_t  buffer_size 
)

Definition at line 709 of file logtape.c.

References Assert, LogicalTape::buffer, LogicalTape::buffer_size, LogicalTape::curBlockNumber, LogicalTape::dirty, LogicalTape::firstBlockNumber, LogicalTape::frozen, ltsReadFillBuffer(), ltsWriteBlock(), LogicalTape::max_size, LogicalTape::nbytes, LogicalTape::nextBlockNumber, palloc(), pfree(), LogicalTape::pos, TapeBlockSetNBytes, LogicalTapeSet::tapes, VALGRIND_MAKE_MEM_DEFINED, and LogicalTape::writing.

Referenced by mergeruns(), and tuplesort_rescan().

710 {
711  LogicalTape *lt;
712 
713  Assert(tapenum >= 0 && tapenum < lts->nTapes);
714  lt = &lts->tapes[tapenum];
715 
716  /*
717  * Round and cap buffer_size if needed.
718  */
719  if (lt->frozen)
720  buffer_size = BLCKSZ;
721  else
722  {
723  /* need at least one block */
724  if (buffer_size < BLCKSZ)
725  buffer_size = BLCKSZ;
726 
727  /* palloc() larger than max_size is unlikely to be helpful */
728  if (buffer_size > lt->max_size)
729  buffer_size = lt->max_size;
730 
731  /* round down to BLCKSZ boundary */
732  buffer_size -= buffer_size % BLCKSZ;
733  }
734 
735  if (lt->writing)
736  {
737  /*
738  * Completion of a write phase. Flush last partial data block, and
739  * rewind for normal (destructive) read.
740  */
741  if (lt->dirty)
742  {
743  /*
744  * As long as we've filled the buffer at least once, its contents
745  * are entirely defined from valgrind's point of view, even though
746  * contents beyond the current end point may be stale. But it's
747  * possible - at least in the case of a parallel sort - to sort
748  * such small amount of data that we do not fill the buffer even
749  * once. Tell valgrind that its contents are defined, so it
750  * doesn't bleat.
751  */
753  lt->buffer_size - lt->nbytes);
754 
755  TapeBlockSetNBytes(lt->buffer, lt->nbytes);
756  ltsWriteBlock(lts, lt->curBlockNumber, (void *) lt->buffer);
757  }
758  lt->writing = false;
759  }
760  else
761  {
762  /*
763  * This is only OK if tape is frozen; we rewind for (another) read
764  * pass.
765  */
766  Assert(lt->frozen);
767  }
768 
769  /* Allocate a read buffer (unless the tape is empty) */
770  if (lt->buffer)
771  pfree(lt->buffer);
772  lt->buffer = NULL;
773  lt->buffer_size = 0;
774  if (lt->firstBlockNumber != -1L)
775  {
776  lt->buffer = palloc(buffer_size);
777  lt->buffer_size = buffer_size;
778  }
779 
780  /* Read the first block, or reset if tape is empty */
782  lt->pos = 0;
783  lt->nbytes = 0;
784  ltsReadFillBuffer(lts, lt);
785 }
int max_size
Definition: logtape.c:155
LogicalTape tapes[FLEXIBLE_ARRAY_MEMBER]
Definition: logtape.c:205
#define VALGRIND_MAKE_MEM_DEFINED(addr, size)
Definition: memdebug.h:26
static bool ltsReadFillBuffer(LogicalTapeSet *lts, LogicalTape *lt)
Definition: logtape.c:286
bool frozen
Definition: logtape.c:131
long nextBlockNumber
Definition: logtape.c:147
bool writing
Definition: logtape.c:130
bool dirty
Definition: logtape.c:132
void pfree(void *pointer)
Definition: mcxt.c:1056
int nbytes
Definition: logtape.c:157
long firstBlockNumber
Definition: logtape.c:145
#define TapeBlockSetNBytes(buf, nbytes)
Definition: logtape.c:114
long curBlockNumber
Definition: logtape.c:146
#define Assert(condition)
Definition: c.h:739
char * buffer
Definition: logtape.c:153
void * palloc(Size size)
Definition: mcxt.c:949
int buffer_size
Definition: logtape.c:154
static void ltsWriteBlock(LogicalTapeSet *lts, long blocknum, void *buffer)
Definition: logtape.c:222

◆ LogicalTapeRewindForWrite()

void LogicalTapeRewindForWrite ( LogicalTapeSet lts,
int  tapenum 
)

Definition at line 796 of file logtape.c.

References Assert, LogicalTape::buffer, LogicalTape::buffer_size, LogicalTape::curBlockNumber, LogicalTape::dirty, LogicalTape::firstBlockNumber, LogicalTape::frozen, LogicalTape::nbytes, pfree(), LogicalTape::pos, LogicalTapeSet::tapes, and LogicalTape::writing.

Referenced by mergeruns(), and tuplesort_gettuple_common().

797 {
798  LogicalTape *lt;
799 
800  Assert(tapenum >= 0 && tapenum < lts->nTapes);
801  lt = &lts->tapes[tapenum];
802 
803  Assert(!lt->writing && !lt->frozen);
804  lt->writing = true;
805  lt->dirty = false;
806  lt->firstBlockNumber = -1L;
807  lt->curBlockNumber = -1L;
808  lt->pos = 0;
809  lt->nbytes = 0;
810  if (lt->buffer)
811  pfree(lt->buffer);
812  lt->buffer = NULL;
813  lt->buffer_size = 0;
814 }
LogicalTape tapes[FLEXIBLE_ARRAY_MEMBER]
Definition: logtape.c:205
bool frozen
Definition: logtape.c:131
bool writing
Definition: logtape.c:130
bool dirty
Definition: logtape.c:132
void pfree(void *pointer)
Definition: mcxt.c:1056
int nbytes
Definition: logtape.c:157
long firstBlockNumber
Definition: logtape.c:145
long curBlockNumber
Definition: logtape.c:146
#define Assert(condition)
Definition: c.h:739
char * buffer
Definition: logtape.c:153
int buffer_size
Definition: logtape.c:154

◆ LogicalTapeSeek()

void LogicalTapeSeek ( LogicalTapeSet lts,
int  tapenum,
long  blocknum,
int  offset 
)

Definition at line 1031 of file logtape.c.

References Assert, LogicalTape::buffer, LogicalTape::buffer_size, LogicalTape::curBlockNumber, elog, ERROR, LogicalTape::frozen, ltsReadBlock(), LogicalTape::nbytes, LogicalTape::nextBlockNumber, LogicalTape::pos, TapeBlockGetTrailer, TapeBlockPayloadSize, and LogicalTapeSet::tapes.

Referenced by tuplesort_restorepos().

1033 {
1034  LogicalTape *lt;
1035 
1036  Assert(tapenum >= 0 && tapenum < lts->nTapes);
1037  lt = &lts->tapes[tapenum];
1038  Assert(lt->frozen);
1039  Assert(offset >= 0 && offset <= TapeBlockPayloadSize);
1040  Assert(lt->buffer_size == BLCKSZ);
1041 
1042  if (blocknum != lt->curBlockNumber)
1043  {
1044  ltsReadBlock(lts, blocknum, (void *) lt->buffer);
1045  lt->curBlockNumber = blocknum;
1047  lt->nextBlockNumber = TapeBlockGetTrailer(lt->buffer)->next;
1048  }
1049 
1050  if (offset > lt->nbytes)
1051  elog(ERROR, "invalid tape seek position");
1052  lt->pos = offset;
1053 }
LogicalTape tapes[FLEXIBLE_ARRAY_MEMBER]
Definition: logtape.c:205
#define TapeBlockPayloadSize
Definition: logtape.c:106
bool frozen
Definition: logtape.c:131
long nextBlockNumber
Definition: logtape.c:147
#define ERROR
Definition: elog.h:43
int nbytes
Definition: logtape.c:157
long curBlockNumber
Definition: logtape.c:146
#define Assert(condition)
Definition: c.h:739
char * buffer
Definition: logtape.c:153
#define elog(elevel,...)
Definition: elog.h:228
int buffer_size
Definition: logtape.c:154
#define TapeBlockGetTrailer(buf)
Definition: logtape.c:107
static void ltsReadBlock(LogicalTapeSet *lts, long blocknum, void *buffer)
Definition: logtape.c:270

◆ LogicalTapeSetBlocks()

long LogicalTapeSetBlocks ( LogicalTapeSet lts)

Definition at line 1082 of file logtape.c.

References LogicalTapeSet::nBlocksAllocated, and LogicalTapeSet::nHoleBlocks.

Referenced by tuplesort_end(), and tuplesort_get_stats().

1083 {
1084  return lts->nBlocksAllocated - lts->nHoleBlocks;
1085 }
long nHoleBlocks
Definition: logtape.c:182
long nBlocksAllocated
Definition: logtape.c:180

◆ LogicalTapeSetClose()

void LogicalTapeSetClose ( LogicalTapeSet lts)

Definition at line 584 of file logtape.c.

References LogicalTape::buffer, BufFileClose(), LogicalTapeSet::freeBlocks, i, LogicalTapeSet::nTapes, LogicalTapeSet::pfile, pfree(), and LogicalTapeSet::tapes.

Referenced by tuplesort_end().

585 {
586  LogicalTape *lt;
587  int i;
588 
589  BufFileClose(lts->pfile);
590  for (i = 0; i < lts->nTapes; i++)
591  {
592  lt = &lts->tapes[i];
593  if (lt->buffer)
594  pfree(lt->buffer);
595  }
596  pfree(lts->freeBlocks);
597  pfree(lts);
598 }
LogicalTape tapes[FLEXIBLE_ARRAY_MEMBER]
Definition: logtape.c:205
BufFile * pfile
Definition: logtape.c:168
void BufFileClose(BufFile *file)
Definition: buffile.c:391
long * freeBlocks
Definition: logtape.c:199
void pfree(void *pointer)
Definition: mcxt.c:1056
char * buffer
Definition: logtape.c:153
int i

◆ LogicalTapeSetCreate()

LogicalTapeSet* LogicalTapeSetCreate ( int  ntapes,
TapeShare shared,
SharedFileSet fileset,
int  worker 
)

Definition at line 510 of file logtape.c.

References Assert, LogicalTapeSet::blocksSorted, LogicalTape::buffer, LogicalTape::buffer_size, BufFileCreateShared(), BufFileCreateTemp(), LogicalTape::curBlockNumber, LogicalTape::dirty, filename, LogicalTape::firstBlockNumber, LogicalTapeSet::forgetFreeSpace, LogicalTapeSet::freeBlocks, LogicalTapeSet::freeBlocksLen, LogicalTape::frozen, i, ltsConcatWorkerTapes(), LogicalTape::max_size, MaxAllocSize, MAXPGPATH, LogicalTapeSet::nBlocksAllocated, LogicalTapeSet::nBlocksWritten, LogicalTape::nbytes, LogicalTape::nextBlockNumber, LogicalTapeSet::nFreeBlocks, LogicalTapeSet::nHoleBlocks, LogicalTapeSet::nTapes, LogicalTape::offsetBlockNumber, offsetof, palloc(), LogicalTapeSet::pfile, pg_itoa(), LogicalTape::pos, LogicalTapeSet::tapes, and LogicalTape::writing.

Referenced by inittapes(), and leader_takeover_tapes().

512 {
513  LogicalTapeSet *lts;
514  LogicalTape *lt;
515  int i;
516 
517  /*
518  * Create top-level struct including per-tape LogicalTape structs.
519  */
520  Assert(ntapes > 0);
521  lts = (LogicalTapeSet *) palloc(offsetof(LogicalTapeSet, tapes) +
522  ntapes * sizeof(LogicalTape));
523  lts->nBlocksAllocated = 0L;
524  lts->nBlocksWritten = 0L;
525  lts->nHoleBlocks = 0L;
526  lts->forgetFreeSpace = false;
527  lts->blocksSorted = true; /* a zero-length array is sorted ... */
528  lts->freeBlocksLen = 32; /* reasonable initial guess */
529  lts->freeBlocks = (long *) palloc(lts->freeBlocksLen * sizeof(long));
530  lts->nFreeBlocks = 0;
531  lts->nTapes = ntapes;
532 
533  /*
534  * Initialize per-tape structs. Note we allocate the I/O buffer and the
535  * first block for a tape only when it is first actually written to. This
536  * avoids wasting memory space when tuplesort.c overestimates the number
537  * of tapes needed.
538  */
539  for (i = 0; i < ntapes; i++)
540  {
541  lt = &lts->tapes[i];
542  lt->writing = true;
543  lt->frozen = false;
544  lt->dirty = false;
545  lt->firstBlockNumber = -1L;
546  lt->curBlockNumber = -1L;
547  lt->nextBlockNumber = -1L;
548  lt->offsetBlockNumber = 0L;
549  lt->buffer = NULL;
550  lt->buffer_size = 0;
551  /* palloc() larger than MaxAllocSize would fail */
552  lt->max_size = MaxAllocSize;
553  lt->pos = 0;
554  lt->nbytes = 0;
555  }
556 
557  /*
558  * Create temp BufFile storage as required.
559  *
560  * Leader concatenates worker tapes, which requires special adjustment to
561  * final tapeset data. Things are simpler for the worker case and the
562  * serial case, though. They are generally very similar -- workers use a
563  * shared fileset, whereas serial sorts use a conventional serial BufFile.
564  */
565  if (shared)
566  ltsConcatWorkerTapes(lts, shared, fileset);
567  else if (fileset)
568  {
569  char filename[MAXPGPATH];
570 
571  pg_itoa(worker, filename);
572  lts->pfile = BufFileCreateShared(fileset, filename);
573  }
574  else
575  lts->pfile = BufFileCreateTemp(false);
576 
577  return lts;
578 }
int max_size
Definition: logtape.c:155
LogicalTape tapes[FLEXIBLE_ARRAY_MEMBER]
Definition: logtape.c:205
int nFreeBlocks
Definition: logtape.c:200
long offsetBlockNumber
Definition: logtape.c:148
long nBlocksWritten
Definition: logtape.c:181
int freeBlocksLen
Definition: logtape.c:201
BufFile * pfile
Definition: logtape.c:168
bool frozen
Definition: logtape.c:131
long nextBlockNumber
Definition: logtape.c:147
bool writing
Definition: logtape.c:130
long * freeBlocks
Definition: logtape.c:199
bool dirty
Definition: logtape.c:132
BufFile * BufFileCreateTemp(bool interXact)
Definition: buffile.c:184
#define MAXPGPATH
BufFile * BufFileCreateShared(SharedFileSet *fileset, const char *name)
Definition: buffile.c:258
long nHoleBlocks
Definition: logtape.c:182
int nbytes
Definition: logtape.c:157
void pg_itoa(int16 i, char *a)
Definition: numutils.c:273
#define MaxAllocSize
Definition: memutils.h:40
long firstBlockNumber
Definition: logtape.c:145
static void ltsConcatWorkerTapes(LogicalTapeSet *lts, TapeShare *shared, SharedFileSet *fileset)
Definition: logtape.c:409
long curBlockNumber
Definition: logtape.c:146
#define Assert(condition)
Definition: c.h:739
char * buffer
Definition: logtape.c:153
static char * filename
Definition: pg_dumpall.c:90
void * palloc(Size size)
Definition: mcxt.c:949
bool forgetFreeSpace
Definition: logtape.c:197
int i
struct LogicalTape LogicalTape
bool blocksSorted
Definition: logtape.c:198
long nBlocksAllocated
Definition: logtape.c:180
int buffer_size
Definition: logtape.c:154
#define offsetof(type, field)
Definition: c.h:662

◆ LogicalTapeSetForgetFreeSpace()

void LogicalTapeSetForgetFreeSpace ( LogicalTapeSet lts)

Definition at line 610 of file logtape.c.

References LogicalTapeSet::forgetFreeSpace.

Referenced by mergeruns().

611 {
612  lts->forgetFreeSpace = true;
613 }
bool forgetFreeSpace
Definition: logtape.c:197

◆ LogicalTapeTell()

void LogicalTapeTell ( LogicalTapeSet lts,
int  tapenum,
long *  blocknum,
int *  offset 
)

Definition at line 1062 of file logtape.c.

References Assert, LogicalTape::buffer_size, LogicalTape::curBlockNumber, LogicalTape::offsetBlockNumber, LogicalTape::pos, and LogicalTapeSet::tapes.

Referenced by tuplesort_markpos().

1064 {
1065  LogicalTape *lt;
1066 
1067  Assert(tapenum >= 0 && tapenum < lts->nTapes);
1068  lt = &lts->tapes[tapenum];
1069  Assert(lt->offsetBlockNumber == 0L);
1070 
1071  /* With a larger buffer, 'pos' wouldn't be the same as offset within page */
1072  Assert(lt->buffer_size == BLCKSZ);
1073 
1074  *blocknum = lt->curBlockNumber;
1075  *offset = lt->pos;
1076 }
LogicalTape tapes[FLEXIBLE_ARRAY_MEMBER]
Definition: logtape.c:205
long offsetBlockNumber
Definition: logtape.c:148
long curBlockNumber
Definition: logtape.c:146
#define Assert(condition)
Definition: c.h:739
int buffer_size
Definition: logtape.c:154

◆ LogicalTapeWrite()

void LogicalTapeWrite ( LogicalTapeSet lts,
int  tapenum,
void *  ptr,
size_t  size 
)

Definition at line 621 of file logtape.c.

References Assert, LogicalTape::buffer, LogicalTape::buffer_size, LogicalTape::curBlockNumber, LogicalTape::dirty, elog, ERROR, LogicalTape::firstBlockNumber, ltsGetFreeBlock(), ltsWriteBlock(), LogicalTape::nbytes, LogicalTape::offsetBlockNumber, palloc(), LogicalTape::pos, TapeBlockGetTrailer, TapeBlockPayloadSize, LogicalTapeSet::tapes, and LogicalTape::writing.

Referenced by markrunend(), writetup_cluster(), writetup_datum(), writetup_heap(), and writetup_index().

623 {
624  LogicalTape *lt;
625  size_t nthistime;
626 
627  Assert(tapenum >= 0 && tapenum < lts->nTapes);
628  lt = &lts->tapes[tapenum];
629  Assert(lt->writing);
630  Assert(lt->offsetBlockNumber == 0L);
631 
632  /* Allocate data buffer and first block on first write */
633  if (lt->buffer == NULL)
634  {
635  lt->buffer = (char *) palloc(BLCKSZ);
636  lt->buffer_size = BLCKSZ;
637  }
638  if (lt->curBlockNumber == -1)
639  {
640  Assert(lt->firstBlockNumber == -1);
641  Assert(lt->pos == 0);
642 
643  lt->curBlockNumber = ltsGetFreeBlock(lts);
645 
646  TapeBlockGetTrailer(lt->buffer)->prev = -1L;
647  }
648 
649  Assert(lt->buffer_size == BLCKSZ);
650  while (size > 0)
651  {
652  if (lt->pos >= TapeBlockPayloadSize)
653  {
654  /* Buffer full, dump it out */
655  long nextBlockNumber;
656 
657  if (!lt->dirty)
658  {
659  /* Hmm, went directly from reading to writing? */
660  elog(ERROR, "invalid logtape state: should be dirty");
661  }
662 
663  /*
664  * First allocate the next block, so that we can store it in the
665  * 'next' pointer of this block.
666  */
667  nextBlockNumber = ltsGetFreeBlock(lts);
668 
669  /* set the next-pointer and dump the current block. */
670  TapeBlockGetTrailer(lt->buffer)->next = nextBlockNumber;
671  ltsWriteBlock(lts, lt->curBlockNumber, (void *) lt->buffer);
672 
673  /* initialize the prev-pointer of the next block */
674  TapeBlockGetTrailer(lt->buffer)->prev = lt->curBlockNumber;
675  lt->curBlockNumber = nextBlockNumber;
676  lt->pos = 0;
677  lt->nbytes = 0;
678  }
679 
680  nthistime = TapeBlockPayloadSize - lt->pos;
681  if (nthistime > size)
682  nthistime = size;
683  Assert(nthistime > 0);
684 
685  memcpy(lt->buffer + lt->pos, ptr, nthistime);
686 
687  lt->dirty = true;
688  lt->pos += nthistime;
689  if (lt->nbytes < lt->pos)
690  lt->nbytes = lt->pos;
691  ptr = (void *) ((char *) ptr + nthistime);
692  size -= nthistime;
693  }
694 }
LogicalTape tapes[FLEXIBLE_ARRAY_MEMBER]
Definition: logtape.c:205
#define TapeBlockPayloadSize
Definition: logtape.c:106
long offsetBlockNumber
Definition: logtape.c:148
static long ltsGetFreeBlock(LogicalTapeSet *lts)
Definition: logtape.c:345
bool writing
Definition: logtape.c:130
bool dirty
Definition: logtape.c:132
#define ERROR
Definition: elog.h:43
int nbytes
Definition: logtape.c:157
long firstBlockNumber
Definition: logtape.c:145
long curBlockNumber
Definition: logtape.c:146
#define Assert(condition)
Definition: c.h:739
char * buffer
Definition: logtape.c:153
void * palloc(Size size)
Definition: mcxt.c:949
#define elog(elevel,...)
Definition: elog.h:228
int buffer_size
Definition: logtape.c:154
static void ltsWriteBlock(LogicalTapeSet *lts, long blocknum, void *buffer)
Definition: logtape.c:222
#define TapeBlockGetTrailer(buf)
Definition: logtape.c:107

◆ ltsConcatWorkerTapes()

static void ltsConcatWorkerTapes ( LogicalTapeSet lts,
TapeShare shared,
SharedFileSet fileset 
)
static

Definition at line 409 of file logtape.c.

References Assert, BufFileAppend(), BufFileOpenShared(), BufFileSize(), filename, TapeShare::firstblocknumber, LogicalTape::firstBlockNumber, i, LogicalTape::max_size, MaxAllocSize, MAXPGPATH, Min, LogicalTapeSet::nBlocksAllocated, LogicalTapeSet::nBlocksWritten, LogicalTapeSet::nHoleBlocks, LogicalTapeSet::nTapes, LogicalTape::offsetBlockNumber, LogicalTapeSet::pfile, pg_itoa(), and LogicalTapeSet::tapes.

Referenced by LogicalTapeSetCreate().

411 {
412  LogicalTape *lt = NULL;
413  long tapeblocks = 0L;
414  long nphysicalblocks = 0L;
415  int i;
416 
417  /* Should have at least one worker tape, plus leader's tape */
418  Assert(lts->nTapes >= 2);
419 
420  /*
421  * Build concatenated view of all BufFiles, remembering the block number
422  * where each source file begins. No changes are needed for leader/last
423  * tape.
424  */
425  for (i = 0; i < lts->nTapes - 1; i++)
426  {
427  char filename[MAXPGPATH];
428  BufFile *file;
429  int64 filesize;
430 
431  lt = &lts->tapes[i];
432 
433  pg_itoa(i, filename);
434  file = BufFileOpenShared(fileset, filename);
435  filesize = BufFileSize(file);
436 
437  /*
438  * Stash first BufFile, and concatenate subsequent BufFiles to that.
439  * Store block offset into each tape as we go.
440  */
441  lt->firstBlockNumber = shared[i].firstblocknumber;
442  if (i == 0)
443  {
444  lts->pfile = file;
445  lt->offsetBlockNumber = 0L;
446  }
447  else
448  {
449  lt->offsetBlockNumber = BufFileAppend(lts->pfile, file);
450  }
451  /* Don't allocate more for read buffer than could possibly help */
452  lt->max_size = Min(MaxAllocSize, filesize);
453  tapeblocks = filesize / BLCKSZ;
454  nphysicalblocks += tapeblocks;
455  }
456 
457  /*
458  * Set # of allocated blocks, as well as # blocks written. Use extent of
459  * new BufFile space (from 0 to end of last worker's tape space) for this.
460  * Allocated/written blocks should include space used by holes left
461  * between concatenated BufFiles.
462  */
463  lts->nBlocksAllocated = lt->offsetBlockNumber + tapeblocks;
464  lts->nBlocksWritten = lts->nBlocksAllocated;
465 
466  /*
467  * Compute number of hole blocks so that we can later work backwards, and
468  * instrument number of physical blocks. We don't simply use physical
469  * blocks directly for instrumentation because this would break if we ever
470  * subsequently wrote to the leader tape.
471  *
472  * Working backwards like this keeps our options open. If shared BufFiles
473  * ever support being written to post-export, logtape.c can automatically
474  * take advantage of that. We'd then support writing to the leader tape
475  * while recycling space from worker tapes, because the leader tape has a
476  * zero offset (write routines won't need to have extra logic to apply an
477  * offset).
478  *
479  * The only thing that currently prevents writing to the leader tape from
480  * working is the fact that BufFiles opened using BufFileOpenShared() are
481  * read-only by definition, but that could be changed if it seemed
482  * worthwhile. For now, writing to the leader tape will raise a "Bad file
483  * descriptor" error, so tuplesort must avoid writing to the leader tape
484  * altogether.
485  */
486  lts->nHoleBlocks = lts->nBlocksAllocated - nphysicalblocks;
487 }
int max_size
Definition: logtape.c:155
LogicalTape tapes[FLEXIBLE_ARRAY_MEMBER]
Definition: logtape.c:205
long offsetBlockNumber
Definition: logtape.c:148
long nBlocksWritten
Definition: logtape.c:181
BufFile * BufFileOpenShared(SharedFileSet *fileset, const char *name)
Definition: buffile.c:280
int64 BufFileSize(BufFile *file)
Definition: buffile.c:785
#define Min(x, y)
Definition: c.h:911
BufFile * pfile
Definition: logtape.c:168
long firstblocknumber
Definition: logtape.h:50
#define MAXPGPATH
long nHoleBlocks
Definition: logtape.c:182
void pg_itoa(int16 i, char *a)
Definition: numutils.c:273
#define MaxAllocSize
Definition: memutils.h:40
long firstBlockNumber
Definition: logtape.c:145
#define Assert(condition)
Definition: c.h:739
static char * filename
Definition: pg_dumpall.c:90
int i
long BufFileAppend(BufFile *target, BufFile *source)
Definition: buffile.c:824
long nBlocksAllocated
Definition: logtape.c:180

◆ ltsGetFreeBlock()

static long ltsGetFreeBlock ( LogicalTapeSet lts)
static

Definition at line 345 of file logtape.c.

References LogicalTapeSet::blocksSorted, LogicalTapeSet::freeBlocks, freeBlocks_cmp(), LogicalTapeSet::nBlocksAllocated, LogicalTapeSet::nFreeBlocks, and qsort.

Referenced by LogicalTapeWrite().

346 {
347  /*
348  * If there are multiple free blocks, we select the one appearing last in
349  * freeBlocks[] (after sorting the array if needed). If there are none,
350  * assign the next block at the end of the file.
351  */
352  if (lts->nFreeBlocks > 0)
353  {
354  if (!lts->blocksSorted)
355  {
356  qsort((void *) lts->freeBlocks, lts->nFreeBlocks,
357  sizeof(long), freeBlocks_cmp);
358  lts->blocksSorted = true;
359  }
360  return lts->freeBlocks[--lts->nFreeBlocks];
361  }
362  else
363  return lts->nBlocksAllocated++;
364 }
int nFreeBlocks
Definition: logtape.c:200
long * freeBlocks
Definition: logtape.c:199
static int freeBlocks_cmp(const void *a, const void *b)
Definition: logtape.c:328
#define qsort(a, b, c, d)
Definition: port.h:488
bool blocksSorted
Definition: logtape.c:198
long nBlocksAllocated
Definition: logtape.c:180

◆ ltsReadBlock()

static void ltsReadBlock ( LogicalTapeSet lts,
long  blocknum,
void *  buffer 
)
static

Definition at line 270 of file logtape.c.

References BufFileRead(), BufFileSeekBlock(), ereport, errcode_for_file_access(), errmsg(), ERROR, and LogicalTapeSet::pfile.

Referenced by LogicalTapeBackspace(), LogicalTapeFreeze(), LogicalTapeSeek(), and ltsReadFillBuffer().

271 {
272  if (BufFileSeekBlock(lts->pfile, blocknum) != 0 ||
273  BufFileRead(lts->pfile, buffer, BLCKSZ) != BLCKSZ)
274  ereport(ERROR,
276  errmsg("could not read block %ld of temporary file: %m",
277  blocknum)));
278 }
BufFile * pfile
Definition: logtape.c:168
#define ERROR
Definition: elog.h:43
int errcode_for_file_access(void)
Definition: elog.c:631
#define ereport(elevel, rest)
Definition: elog.h:141
int BufFileSeekBlock(BufFile *file, long blknum)
Definition: buffile.c:752
int errmsg(const char *fmt,...)
Definition: elog.c:822
size_t BufFileRead(BufFile *file, void *ptr, size_t size)
Definition: buffile.c:528

◆ ltsReadFillBuffer()

static bool ltsReadFillBuffer ( LogicalTapeSet lts,
LogicalTape lt 
)
static

Definition at line 286 of file logtape.c.

References LogicalTape::buffer, LogicalTape::buffer_size, LogicalTape::curBlockNumber, LogicalTape::frozen, ltsReadBlock(), ltsReleaseBlock(), LogicalTape::nbytes, LogicalTape::nextBlockNumber, LogicalTape::offsetBlockNumber, LogicalTape::pos, TapeBlockGetNBytes, TapeBlockGetTrailer, and TapeBlockIsLast.

Referenced by LogicalTapeRead(), and LogicalTapeRewindForRead().

287 {
288  lt->pos = 0;
289  lt->nbytes = 0;
290 
291  do
292  {
293  char *thisbuf = lt->buffer + lt->nbytes;
294  long datablocknum = lt->nextBlockNumber;
295 
296  /* Fetch next block number */
297  if (datablocknum == -1L)
298  break; /* EOF */
299  /* Apply worker offset, needed for leader tapesets */
300  datablocknum += lt->offsetBlockNumber;
301 
302  /* Read the block */
303  ltsReadBlock(lts, datablocknum, (void *) thisbuf);
304  if (!lt->frozen)
305  ltsReleaseBlock(lts, datablocknum);
307 
308  lt->nbytes += TapeBlockGetNBytes(thisbuf);
309  if (TapeBlockIsLast(thisbuf))
310  {
311  lt->nextBlockNumber = -1L;
312  /* EOF */
313  break;
314  }
315  else
316  lt->nextBlockNumber = TapeBlockGetTrailer(thisbuf)->next;
317 
318  /* Advance to next block, if we have buffer space left */
319  } while (lt->buffer_size - lt->nbytes > BLCKSZ);
320 
321  return (lt->nbytes > 0);
322 }
#define TapeBlockIsLast(buf)
Definition: logtape.c:110
long offsetBlockNumber
Definition: logtape.c:148
static void ltsReleaseBlock(LogicalTapeSet *lts, long blocknum)
Definition: logtape.c:370
bool frozen
Definition: logtape.c:131
long nextBlockNumber
Definition: logtape.c:147
int nbytes
Definition: logtape.c:157
long curBlockNumber
Definition: logtape.c:146
#define TapeBlockGetNBytes(buf)
Definition: logtape.c:111
char * buffer
Definition: logtape.c:153
int buffer_size
Definition: logtape.c:154
#define TapeBlockGetTrailer(buf)
Definition: logtape.c:107
static void ltsReadBlock(LogicalTapeSet *lts, long blocknum, void *buffer)
Definition: logtape.c:270

◆ ltsReleaseBlock()

static void ltsReleaseBlock ( LogicalTapeSet lts,
long  blocknum 
)
static

Definition at line 370 of file logtape.c.

References LogicalTapeSet::blocksSorted, LogicalTapeSet::forgetFreeSpace, LogicalTapeSet::freeBlocks, LogicalTapeSet::freeBlocksLen, LogicalTapeSet::nFreeBlocks, and repalloc().

Referenced by ltsReadFillBuffer().

371 {
372  int ndx;
373 
374  /*
375  * Do nothing if we're no longer interested in remembering free space.
376  */
377  if (lts->forgetFreeSpace)
378  return;
379 
380  /*
381  * Enlarge freeBlocks array if full.
382  */
383  if (lts->nFreeBlocks >= lts->freeBlocksLen)
384  {
385  lts->freeBlocksLen *= 2;
386  lts->freeBlocks = (long *) repalloc(lts->freeBlocks,
387  lts->freeBlocksLen * sizeof(long));
388  }
389 
390  /*
391  * Add blocknum to array, and mark the array unsorted if it's no longer in
392  * decreasing order.
393  */
394  ndx = lts->nFreeBlocks++;
395  lts->freeBlocks[ndx] = blocknum;
396  if (ndx > 0 && lts->freeBlocks[ndx - 1] < blocknum)
397  lts->blocksSorted = false;
398 }
int nFreeBlocks
Definition: logtape.c:200
int freeBlocksLen
Definition: logtape.c:201
long * freeBlocks
Definition: logtape.c:199
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1069
bool forgetFreeSpace
Definition: logtape.c:197
bool blocksSorted
Definition: logtape.c:198

◆ ltsWriteBlock()

static void ltsWriteBlock ( LogicalTapeSet lts,
long  blocknum,
void *  buffer 
)
static

Definition at line 222 of file logtape.c.

References BufFileSeekBlock(), BufFileWrite(), PGAlignedBlock::data, ereport, errcode_for_file_access(), errmsg(), ERROR, MemSet, LogicalTapeSet::nBlocksWritten, and LogicalTapeSet::pfile.

Referenced by LogicalTapeFreeze(), LogicalTapeRewindForRead(), and LogicalTapeWrite().

223 {
224  /*
225  * BufFile does not support "holes", so if we're about to write a block
226  * that's past the current end of file, fill the space between the current
227  * end of file and the target block with zeros.
228  *
229  * This should happen rarely, otherwise you are not writing very
230  * sequentially. In current use, this only happens when the sort ends
231  * writing a run, and switches to another tape. The last block of the
232  * previous tape isn't flushed to disk until the end of the sort, so you
233  * get one-block hole, where the last block of the previous tape will
234  * later go.
235  *
236  * Note that BufFile concatenation can leave "holes" in BufFile between
237  * worker-owned block ranges. These are tracked for reporting purposes
238  * only. We never read from nor write to these hole blocks, and so they
239  * are not considered here.
240  */
241  while (blocknum > lts->nBlocksWritten)
242  {
243  PGAlignedBlock zerobuf;
244 
245  MemSet(zerobuf.data, 0, sizeof(zerobuf));
246 
247  ltsWriteBlock(lts, lts->nBlocksWritten, zerobuf.data);
248  }
249 
250  /* Write the requested block */
251  if (BufFileSeekBlock(lts->pfile, blocknum) != 0 ||
252  BufFileWrite(lts->pfile, buffer, BLCKSZ) != BLCKSZ)
253  ereport(ERROR,
255  errmsg("could not write block %ld of temporary file: %m",
256  blocknum)));
257 
258  /* Update nBlocksWritten, if we extended the file */
259  if (blocknum == lts->nBlocksWritten)
260  lts->nBlocksWritten++;
261 }
long nBlocksWritten
Definition: logtape.c:181
BufFile * pfile
Definition: logtape.c:168
#define MemSet(start, val, len)
Definition: c.h:962
char data[BLCKSZ]
Definition: c.h:1091
#define ERROR
Definition: elog.h:43
int errcode_for_file_access(void)
Definition: elog.c:631
#define ereport(elevel, rest)
Definition: elog.h:141
int BufFileSeekBlock(BufFile *file, long blknum)
Definition: buffile.c:752
int errmsg(const char *fmt,...)
Definition: elog.c:822
size_t BufFileWrite(BufFile *file, void *ptr, size_t size)
Definition: buffile.c:575
static void ltsWriteBlock(LogicalTapeSet *lts, long blocknum, void *buffer)
Definition: logtape.c:222