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))
 
#define TAPE_WRITE_PREALLOC_MIN   8
 
#define TAPE_WRITE_PREALLOC_MAX   128
 

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 long ltsGetPreallocBlock (LogicalTapeSet *lts, LogicalTape *lt)
 
static void ltsReleaseBlock (LogicalTapeSet *lts, long blocknum)
 
static void ltsConcatWorkerTapes (LogicalTapeSet *lts, TapeShare *shared, SharedFileSet *fileset)
 
static void ltsInitTape (LogicalTape *lt)
 
static void ltsInitReadBuffer (LogicalTapeSet *lts, LogicalTape *lt)
 
static bool ltsReadFillBuffer (LogicalTapeSet *lts, LogicalTape *lt)
 
static void swap_nodes (long *heap, unsigned long a, unsigned long b)
 
static unsigned long left_offset (unsigned long i)
 
static unsigned long right_offset (unsigned i)
 
static unsigned long parent_offset (unsigned long i)
 
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)
 
void LogicalTapeSetExtend (LogicalTapeSet *lts, int nAdditional)
 
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

◆ TAPE_WRITE_PREALLOC_MAX

#define TAPE_WRITE_PREALLOC_MAX   128

Definition at line 124 of file logtape.c.

Referenced by ltsGetPreallocBlock().

◆ TAPE_WRITE_PREALLOC_MIN

#define TAPE_WRITE_PREALLOC_MIN   8

Definition at line 123 of file logtape.c.

Referenced by ltsGetPreallocBlock().

◆ TapeBlockGetNBytes

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

Definition at line 107 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 106 of file logtape.c.

Referenced by LogicalTapeFreeze(), and ltsReadFillBuffer().

◆ TapeBlockPayloadSize

#define TapeBlockPayloadSize   (BLCKSZ - sizeof(TapeBlockTrailer))

Definition at line 102 of file logtape.c.

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

◆ TapeBlockSetNBytes

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

Definition at line 110 of file logtape.c.

Referenced by LogicalTapeFreeze(), and LogicalTapeRewindForRead().

Typedef Documentation

◆ LogicalTape

typedef struct LogicalTape LogicalTape

◆ TapeBlockTrailer

Function Documentation

◆ left_offset()

static unsigned long left_offset ( unsigned long  i)
inlinestatic

Definition at line 349 of file logtape.c.

Referenced by ltsGetFreeBlock().

350 {
351  return 2 * i + 1;
352 }
int i

◆ LogicalTapeBackspace()

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

Definition at line 1116 of file logtape.c.

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

Referenced by tuplesort_gettuple_common().

1117 {
1118  LogicalTape *lt;
1119  size_t seekpos = 0;
1120 
1121  Assert(tapenum >= 0 && tapenum < lts->nTapes);
1122  lt = &lts->tapes[tapenum];
1123  Assert(lt->frozen);
1124  Assert(lt->buffer_size == BLCKSZ);
1125 
1126  if (lt->buffer == NULL)
1127  ltsInitReadBuffer(lts, lt);
1128 
1129  /*
1130  * Easy case for seek within current block.
1131  */
1132  if (size <= (size_t) lt->pos)
1133  {
1134  lt->pos -= (int) size;
1135  return size;
1136  }
1137 
1138  /*
1139  * Not-so-easy case, have to walk back the chain of blocks. This
1140  * implementation would be pretty inefficient for long seeks, but we
1141  * really aren't doing that (a seek over one tuple is typical).
1142  */
1143  seekpos = (size_t) lt->pos; /* part within this block */
1144  while (size > seekpos)
1145  {
1146  long prev = TapeBlockGetTrailer(lt->buffer)->prev;
1147 
1148  if (prev == -1L)
1149  {
1150  /* Tried to back up beyond the beginning of tape. */
1151  if (lt->curBlockNumber != lt->firstBlockNumber)
1152  elog(ERROR, "unexpected end of tape");
1153  lt->pos = 0;
1154  return seekpos;
1155  }
1156 
1157  ltsReadBlock(lts, prev, (void *) lt->buffer);
1158 
1159  if (TapeBlockGetTrailer(lt->buffer)->next != lt->curBlockNumber)
1160  elog(ERROR, "broken tape, next of block %ld is %ld, expected %ld",
1161  prev,
1162  TapeBlockGetTrailer(lt->buffer)->next,
1163  lt->curBlockNumber);
1164 
1166  lt->curBlockNumber = prev;
1167  lt->nextBlockNumber = TapeBlockGetTrailer(lt->buffer)->next;
1168 
1169  seekpos += TapeBlockPayloadSize;
1170  }
1171 
1172  /*
1173  * 'seekpos' can now be greater than 'size', because it points to the
1174  * beginning the target block. The difference is the position within the
1175  * page.
1176  */
1177  lt->pos = seekpos - size;
1178  return size;
1179 }
#define TapeBlockPayloadSize
Definition: logtape.c:102
bool frozen
Definition: logtape.c:139
long nextBlockNumber
Definition: logtape.c:155
#define ERROR
Definition: elog.h:43
int nbytes
Definition: logtape.c:165
long firstBlockNumber
Definition: logtape.c:153
static void ltsInitReadBuffer(LogicalTapeSet *lts, LogicalTape *lt)
Definition: logtape.c:632
long curBlockNumber
Definition: logtape.c:154
#define Assert(condition)
Definition: c.h:738
LogicalTape * tapes
Definition: logtape.c:216
char * buffer
Definition: logtape.c:161
#define elog(elevel,...)
Definition: elog.h:214
int buffer_size
Definition: logtape.c:162
#define TapeBlockGetTrailer(buf)
Definition: logtape.c:103
static void ltsReadBlock(LogicalTapeSet *lts, long blocknum, void *buffer)
Definition: logtape.c:284

◆ LogicalTapeFreeze()

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

Definition at line 1013 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().

1014 {
1015  LogicalTape *lt;
1016 
1017  Assert(tapenum >= 0 && tapenum < lts->nTapes);
1018  lt = &lts->tapes[tapenum];
1019  Assert(lt->writing);
1020  Assert(lt->offsetBlockNumber == 0L);
1021 
1022  /*
1023  * Completion of a write phase. Flush last partial data block, and rewind
1024  * for nondestructive read.
1025  */
1026  if (lt->dirty)
1027  {
1028  /*
1029  * As long as we've filled the buffer at least once, its contents are
1030  * entirely defined from valgrind's point of view, even though
1031  * contents beyond the current end point may be stale. But it's
1032  * possible - at least in the case of a parallel sort - to sort such
1033  * small amount of data that we do not fill the buffer even once. Tell
1034  * valgrind that its contents are defined, so it doesn't bleat.
1035  */
1037  lt->buffer_size - lt->nbytes);
1038 
1039  TapeBlockSetNBytes(lt->buffer, lt->nbytes);
1040  ltsWriteBlock(lts, lt->curBlockNumber, (void *) lt->buffer);
1041  lt->writing = false;
1042  }
1043  lt->writing = false;
1044  lt->frozen = true;
1045 
1046  /*
1047  * The seek and backspace functions assume a single block read buffer.
1048  * That's OK with current usage. A larger buffer is helpful to make the
1049  * read pattern of the backing file look more sequential to the OS, when
1050  * we're reading from multiple tapes. But at the end of a sort, when a
1051  * tape is frozen, we only read from a single tape anyway.
1052  */
1053  if (!lt->buffer || lt->buffer_size != BLCKSZ)
1054  {
1055  if (lt->buffer)
1056  pfree(lt->buffer);
1057  lt->buffer = palloc(BLCKSZ);
1058  lt->buffer_size = BLCKSZ;
1059  }
1060 
1061  /* Read the first block, or reset if tape is empty */
1062  lt->curBlockNumber = lt->firstBlockNumber;
1063  lt->pos = 0;
1064  lt->nbytes = 0;
1065 
1066  if (lt->firstBlockNumber == -1L)
1067  lt->nextBlockNumber = -1L;
1068  ltsReadBlock(lts, lt->curBlockNumber, (void *) lt->buffer);
1069  if (TapeBlockIsLast(lt->buffer))
1070  lt->nextBlockNumber = -1L;
1071  else
1072  lt->nextBlockNumber = TapeBlockGetTrailer(lt->buffer)->next;
1073  lt->nbytes = TapeBlockGetNBytes(lt->buffer);
1074 
1075  /* Handle extra steps when caller is to share its tapeset */
1076  if (share)
1077  {
1078  BufFileExportShared(lts->pfile);
1079  share->firstblocknumber = lt->firstBlockNumber;
1080  }
1081 }
#define VALGRIND_MAKE_MEM_DEFINED(addr, size)
Definition: memdebug.h:26
#define TapeBlockIsLast(buf)
Definition: logtape.c:106
long offsetBlockNumber
Definition: logtape.c:156
BufFile * pfile
Definition: logtape.c:185
long firstblocknumber
Definition: logtape.h:50
bool frozen
Definition: logtape.c:139
long nextBlockNumber
Definition: logtape.c:155
bool writing
Definition: logtape.c:138
bool dirty
Definition: logtape.c:140
void pfree(void *pointer)
Definition: mcxt.c:1056
int nbytes
Definition: logtape.c:165
long firstBlockNumber
Definition: logtape.c:153
#define TapeBlockSetNBytes(buf, nbytes)
Definition: logtape.c:110
long curBlockNumber
Definition: logtape.c:154
#define Assert(condition)
Definition: c.h:738
void BufFileExportShared(BufFile *file)
Definition: buffile.c:373
LogicalTape * tapes
Definition: logtape.c:216
#define TapeBlockGetNBytes(buf)
Definition: logtape.c:107
char * buffer
Definition: logtape.c:161
void * palloc(Size size)
Definition: mcxt.c:949
int buffer_size
Definition: logtape.c:162
static void ltsWriteBlock(LogicalTapeSet *lts, long blocknum, void *buffer)
Definition: logtape.c:236
#define TapeBlockGetTrailer(buf)
Definition: logtape.c:103
static void ltsReadBlock(LogicalTapeSet *lts, long blocknum, void *buffer)
Definition: logtape.c:284

◆ LogicalTapeRead()

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

Definition at line 956 of file logtape.c.

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

Referenced by getlen(), and hashagg_batch_read().

958 {
959  LogicalTape *lt;
960  size_t nread = 0;
961  size_t nthistime;
962 
963  Assert(tapenum >= 0 && tapenum < lts->nTapes);
964  lt = &lts->tapes[tapenum];
965  Assert(!lt->writing);
966 
967  if (lt->buffer == NULL)
968  ltsInitReadBuffer(lts, lt);
969 
970  while (size > 0)
971  {
972  if (lt->pos >= lt->nbytes)
973  {
974  /* Try to load more data into buffer. */
975  if (!ltsReadFillBuffer(lts, lt))
976  break; /* EOF */
977  }
978 
979  nthistime = lt->nbytes - lt->pos;
980  if (nthistime > size)
981  nthistime = size;
982  Assert(nthistime > 0);
983 
984  memcpy(ptr, lt->buffer + lt->pos, nthistime);
985 
986  lt->pos += nthistime;
987  ptr = (void *) ((char *) ptr + nthistime);
988  size -= nthistime;
989  nread += nthistime;
990  }
991 
992  return nread;
993 }
static bool ltsReadFillBuffer(LogicalTapeSet *lts, LogicalTape *lt)
Definition: logtape.c:300
bool writing
Definition: logtape.c:138
int nbytes
Definition: logtape.c:165
static void ltsInitReadBuffer(LogicalTapeSet *lts, LogicalTape *lt)
Definition: logtape.c:632
#define Assert(condition)
Definition: c.h:738
LogicalTape * tapes
Definition: logtape.c:216
char * buffer
Definition: logtape.c:161

◆ LogicalTapeRewindForRead()

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

Definition at line 842 of file logtape.c.

References Assert, LogicalTape::buffer, LogicalTape::buffer_size, LogicalTape::curBlockNumber, LogicalTape::dirty, LogicalTape::frozen, i, ltsReleaseBlock(), ltsWriteBlock(), LogicalTape::max_size, LogicalTape::nbytes, LogicalTape::nprealloc, pfree(), LogicalTape::prealloc, LogicalTape::prealloc_size, TapeBlockSetNBytes, LogicalTapeSet::tapes, VALGRIND_MAKE_MEM_DEFINED, and LogicalTape::writing.

Referenced by agg_refill_hash_table(), mergeruns(), and tuplesort_rescan().

843 {
844  LogicalTape *lt;
845 
846  Assert(tapenum >= 0 && tapenum < lts->nTapes);
847  lt = &lts->tapes[tapenum];
848 
849  /*
850  * Round and cap buffer_size if needed.
851  */
852  if (lt->frozen)
853  buffer_size = BLCKSZ;
854  else
855  {
856  /* need at least one block */
857  if (buffer_size < BLCKSZ)
858  buffer_size = BLCKSZ;
859 
860  /* palloc() larger than max_size is unlikely to be helpful */
861  if (buffer_size > lt->max_size)
862  buffer_size = lt->max_size;
863 
864  /* round down to BLCKSZ boundary */
865  buffer_size -= buffer_size % BLCKSZ;
866  }
867 
868  if (lt->writing)
869  {
870  /*
871  * Completion of a write phase. Flush last partial data block, and
872  * rewind for normal (destructive) read.
873  */
874  if (lt->dirty)
875  {
876  /*
877  * As long as we've filled the buffer at least once, its contents
878  * are entirely defined from valgrind's point of view, even though
879  * contents beyond the current end point may be stale. But it's
880  * possible - at least in the case of a parallel sort - to sort
881  * such small amount of data that we do not fill the buffer even
882  * once. Tell valgrind that its contents are defined, so it
883  * doesn't bleat.
884  */
886  lt->buffer_size - lt->nbytes);
887 
888  TapeBlockSetNBytes(lt->buffer, lt->nbytes);
889  ltsWriteBlock(lts, lt->curBlockNumber, (void *) lt->buffer);
890  }
891  lt->writing = false;
892  }
893  else
894  {
895  /*
896  * This is only OK if tape is frozen; we rewind for (another) read
897  * pass.
898  */
899  Assert(lt->frozen);
900  }
901 
902  if (lt->buffer)
903  pfree(lt->buffer);
904 
905  /* the buffer is lazily allocated, but set the size here */
906  lt->buffer = NULL;
907  lt->buffer_size = buffer_size;
908 
909  /* free the preallocation list, and return unused block numbers */
910  if (lt->prealloc != NULL)
911  {
912  for (int i = lt->nprealloc; i > 0; i--)
913  ltsReleaseBlock(lts, lt->prealloc[i - 1]);
914  pfree(lt->prealloc);
915  lt->prealloc = NULL;
916  lt->nprealloc = 0;
917  lt->prealloc_size = 0;
918  }
919 }
int max_size
Definition: logtape.c:163
#define VALGRIND_MAKE_MEM_DEFINED(addr, size)
Definition: memdebug.h:26
long * prealloc
Definition: logtape.c:172
int prealloc_size
Definition: logtape.c:174
static void ltsReleaseBlock(LogicalTapeSet *lts, long blocknum)
Definition: logtape.c:465
bool frozen
Definition: logtape.c:139
bool writing
Definition: logtape.c:138
bool dirty
Definition: logtape.c:140
void pfree(void *pointer)
Definition: mcxt.c:1056
int nbytes
Definition: logtape.c:165
int nprealloc
Definition: logtape.c:173
#define TapeBlockSetNBytes(buf, nbytes)
Definition: logtape.c:110
long curBlockNumber
Definition: logtape.c:154
#define Assert(condition)
Definition: c.h:738
LogicalTape * tapes
Definition: logtape.c:216
char * buffer
Definition: logtape.c:161
int i
int buffer_size
Definition: logtape.c:162
static void ltsWriteBlock(LogicalTapeSet *lts, long blocknum, void *buffer)
Definition: logtape.c:236

◆ LogicalTapeRewindForWrite()

void LogicalTapeRewindForWrite ( LogicalTapeSet lts,
int  tapenum 
)

Definition at line 930 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 hashagg_tapeinfo_release(), mergeruns(), and tuplesort_gettuple_common().

931 {
932  LogicalTape *lt;
933 
934  Assert(tapenum >= 0 && tapenum < lts->nTapes);
935  lt = &lts->tapes[tapenum];
936 
937  Assert(!lt->writing && !lt->frozen);
938  lt->writing = true;
939  lt->dirty = false;
940  lt->firstBlockNumber = -1L;
941  lt->curBlockNumber = -1L;
942  lt->pos = 0;
943  lt->nbytes = 0;
944  if (lt->buffer)
945  pfree(lt->buffer);
946  lt->buffer = NULL;
947  lt->buffer_size = 0;
948 }
bool frozen
Definition: logtape.c:139
bool writing
Definition: logtape.c:138
bool dirty
Definition: logtape.c:140
void pfree(void *pointer)
Definition: mcxt.c:1056
int nbytes
Definition: logtape.c:165
long firstBlockNumber
Definition: logtape.c:153
long curBlockNumber
Definition: logtape.c:154
#define Assert(condition)
Definition: c.h:738
LogicalTape * tapes
Definition: logtape.c:216
char * buffer
Definition: logtape.c:161
int buffer_size
Definition: logtape.c:162

◆ LogicalTapeSeek()

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

Definition at line 1190 of file logtape.c.

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

Referenced by tuplesort_restorepos().

1192 {
1193  LogicalTape *lt;
1194 
1195  Assert(tapenum >= 0 && tapenum < lts->nTapes);
1196  lt = &lts->tapes[tapenum];
1197  Assert(lt->frozen);
1198  Assert(offset >= 0 && offset <= TapeBlockPayloadSize);
1199  Assert(lt->buffer_size == BLCKSZ);
1200 
1201  if (lt->buffer == NULL)
1202  ltsInitReadBuffer(lts, lt);
1203 
1204  if (blocknum != lt->curBlockNumber)
1205  {
1206  ltsReadBlock(lts, blocknum, (void *) lt->buffer);
1207  lt->curBlockNumber = blocknum;
1209  lt->nextBlockNumber = TapeBlockGetTrailer(lt->buffer)->next;
1210  }
1211 
1212  if (offset > lt->nbytes)
1213  elog(ERROR, "invalid tape seek position");
1214  lt->pos = offset;
1215 }
#define TapeBlockPayloadSize
Definition: logtape.c:102
bool frozen
Definition: logtape.c:139
long nextBlockNumber
Definition: logtape.c:155
#define ERROR
Definition: elog.h:43
int nbytes
Definition: logtape.c:165
static void ltsInitReadBuffer(LogicalTapeSet *lts, LogicalTape *lt)
Definition: logtape.c:632
long curBlockNumber
Definition: logtape.c:154
#define Assert(condition)
Definition: c.h:738
LogicalTape * tapes
Definition: logtape.c:216
char * buffer
Definition: logtape.c:161
#define elog(elevel,...)
Definition: elog.h:214
int buffer_size
Definition: logtape.c:162
#define TapeBlockGetTrailer(buf)
Definition: logtape.c:103
static void ltsReadBlock(LogicalTapeSet *lts, long blocknum, void *buffer)
Definition: logtape.c:284

◆ LogicalTapeSetBlocks()

long LogicalTapeSetBlocks ( LogicalTapeSet lts)

Definition at line 1248 of file logtape.c.

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

Referenced by hash_agg_update_metrics(), tuplesort_free(), and tuplesort_updatemax().

1249 {
1250  return lts->nBlocksAllocated - lts->nHoleBlocks;
1251 }
long nHoleBlocks
Definition: logtape.c:199
long nBlocksAllocated
Definition: logtape.c:197

◆ LogicalTapeSetClose()

void LogicalTapeSetClose ( LogicalTapeSet lts)

Definition at line 716 of file logtape.c.

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

Referenced by hashagg_reset_spill_state(), and tuplesort_free().

717 {
718  LogicalTape *lt;
719  int i;
720 
721  BufFileClose(lts->pfile);
722  for (i = 0; i < lts->nTapes; i++)
723  {
724  lt = &lts->tapes[i];
725  if (lt->buffer)
726  pfree(lt->buffer);
727  }
728  pfree(lts->tapes);
729  pfree(lts->freeBlocks);
730  pfree(lts);
731 }
BufFile * pfile
Definition: logtape.c:185
void BufFileClose(BufFile *file)
Definition: buffile.c:391
long * freeBlocks
Definition: logtape.c:210
void pfree(void *pointer)
Definition: mcxt.c:1056
LogicalTape * tapes
Definition: logtape.c:216
char * buffer
Definition: logtape.c:161
int i

◆ LogicalTapeSetCreate()

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

Definition at line 665 of file logtape.c.

References Assert, BufFileCreateShared(), BufFileCreateTemp(), filename, LogicalTapeSet::forgetFreeSpace, LogicalTapeSet::freeBlocks, LogicalTapeSet::freeBlocksLen, i, ltsConcatWorkerTapes(), ltsInitTape(), MAXPGPATH, LogicalTapeSet::nBlocksAllocated, LogicalTapeSet::nBlocksWritten, LogicalTapeSet::nFreeBlocks, LogicalTapeSet::nHoleBlocks, LogicalTapeSet::nTapes, palloc(), LogicalTapeSet::pfile, pg_itoa(), and LogicalTapeSet::tapes.

Referenced by hashagg_tapeinfo_init(), inittapes(), and leader_takeover_tapes().

667 {
668  LogicalTapeSet *lts;
669  int i;
670 
671  /*
672  * Create top-level struct including per-tape LogicalTape structs.
673  */
674  Assert(ntapes > 0);
675  lts = (LogicalTapeSet *) palloc(sizeof(LogicalTapeSet));
676  lts->nBlocksAllocated = 0L;
677  lts->nBlocksWritten = 0L;
678  lts->nHoleBlocks = 0L;
679  lts->forgetFreeSpace = false;
680  lts->freeBlocksLen = 32; /* reasonable initial guess */
681  lts->freeBlocks = (long *) palloc(lts->freeBlocksLen * sizeof(long));
682  lts->nFreeBlocks = 0;
683  lts->nTapes = ntapes;
684  lts->tapes = (LogicalTape *) palloc(ntapes * sizeof(LogicalTape));
685 
686  for (i = 0; i < ntapes; i++)
687  ltsInitTape(&lts->tapes[i]);
688 
689  /*
690  * Create temp BufFile storage as required.
691  *
692  * Leader concatenates worker tapes, which requires special adjustment to
693  * final tapeset data. Things are simpler for the worker case and the
694  * serial case, though. They are generally very similar -- workers use a
695  * shared fileset, whereas serial sorts use a conventional serial BufFile.
696  */
697  if (shared)
698  ltsConcatWorkerTapes(lts, shared, fileset);
699  else if (fileset)
700  {
701  char filename[MAXPGPATH];
702 
703  pg_itoa(worker, filename);
704  lts->pfile = BufFileCreateShared(fileset, filename);
705  }
706  else
707  lts->pfile = BufFileCreateTemp(false);
708 
709  return lts;
710 }
long nBlocksWritten
Definition: logtape.c:198
BufFile * pfile
Definition: logtape.c:185
long * freeBlocks
Definition: logtape.c:210
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:199
void pg_itoa(int16 i, char *a)
Definition: numutils.c:337
static void ltsInitTape(LogicalTape *lt)
Definition: logtape.c:606
long nFreeBlocks
Definition: logtape.c:211
static void ltsConcatWorkerTapes(LogicalTapeSet *lts, TapeShare *shared, SharedFileSet *fileset)
Definition: logtape.c:522
#define Assert(condition)
Definition: c.h:738
LogicalTape * tapes
Definition: logtape.c:216
static char * filename
Definition: pg_dumpall.c:90
void * palloc(Size size)
Definition: mcxt.c:949
bool forgetFreeSpace
Definition: logtape.c:209
int i
Size freeBlocksLen
Definition: logtape.c:212
long nBlocksAllocated
Definition: logtape.c:197

◆ LogicalTapeSetExtend()

void LogicalTapeSetExtend ( LogicalTapeSet lts,
int  nAdditional 
)

Definition at line 1088 of file logtape.c.

References i, ltsInitTape(), LogicalTapeSet::nTapes, repalloc(), and LogicalTapeSet::tapes.

Referenced by hashagg_tapeinfo_assign().

1089 {
1090  int i;
1091  int nTapesOrig = lts->nTapes;
1092 
1093  lts->nTapes += nAdditional;
1094 
1095  lts->tapes = (LogicalTape *) repalloc(lts->tapes,
1096  lts->nTapes * sizeof(LogicalTape));
1097 
1098  for (i = nTapesOrig; i < lts->nTapes; i++)
1099  ltsInitTape(&lts->tapes[i]);
1100 }
static void ltsInitTape(LogicalTape *lt)
Definition: logtape.c:606
LogicalTape * tapes
Definition: logtape.c:216
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1069
int i

◆ LogicalTapeSetForgetFreeSpace()

void LogicalTapeSetForgetFreeSpace ( LogicalTapeSet lts)

Definition at line 743 of file logtape.c.

References LogicalTapeSet::forgetFreeSpace.

Referenced by mergeruns().

744 {
745  lts->forgetFreeSpace = true;
746 }
bool forgetFreeSpace
Definition: logtape.c:209

◆ LogicalTapeTell()

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

Definition at line 1224 of file logtape.c.

References Assert, LogicalTape::buffer, LogicalTape::buffer_size, LogicalTape::curBlockNumber, ltsInitReadBuffer(), LogicalTape::offsetBlockNumber, LogicalTape::pos, and LogicalTapeSet::tapes.

Referenced by tuplesort_markpos().

1226 {
1227  LogicalTape *lt;
1228 
1229  Assert(tapenum >= 0 && tapenum < lts->nTapes);
1230  lt = &lts->tapes[tapenum];
1231 
1232  if (lt->buffer == NULL)
1233  ltsInitReadBuffer(lts, lt);
1234 
1235  Assert(lt->offsetBlockNumber == 0L);
1236 
1237  /* With a larger buffer, 'pos' wouldn't be the same as offset within page */
1238  Assert(lt->buffer_size == BLCKSZ);
1239 
1240  *blocknum = lt->curBlockNumber;
1241  *offset = lt->pos;
1242 }
long offsetBlockNumber
Definition: logtape.c:156
static void ltsInitReadBuffer(LogicalTapeSet *lts, LogicalTape *lt)
Definition: logtape.c:632
long curBlockNumber
Definition: logtape.c:154
#define Assert(condition)
Definition: c.h:738
LogicalTape * tapes
Definition: logtape.c:216
char * buffer
Definition: logtape.c:161
int buffer_size
Definition: logtape.c:162

◆ LogicalTapeWrite()

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

Definition at line 754 of file logtape.c.

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

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

756 {
757  LogicalTape *lt;
758  size_t nthistime;
759 
760  Assert(tapenum >= 0 && tapenum < lts->nTapes);
761  lt = &lts->tapes[tapenum];
762  Assert(lt->writing);
763  Assert(lt->offsetBlockNumber == 0L);
764 
765  /* Allocate data buffer and first block on first write */
766  if (lt->buffer == NULL)
767  {
768  lt->buffer = (char *) palloc(BLCKSZ);
769  lt->buffer_size = BLCKSZ;
770  }
771  if (lt->curBlockNumber == -1)
772  {
773  Assert(lt->firstBlockNumber == -1);
774  Assert(lt->pos == 0);
775 
776  lt->curBlockNumber = ltsGetPreallocBlock(lts, lt);
778 
779  TapeBlockGetTrailer(lt->buffer)->prev = -1L;
780  }
781 
782  Assert(lt->buffer_size == BLCKSZ);
783  while (size > 0)
784  {
785  if (lt->pos >= TapeBlockPayloadSize)
786  {
787  /* Buffer full, dump it out */
788  long nextBlockNumber;
789 
790  if (!lt->dirty)
791  {
792  /* Hmm, went directly from reading to writing? */
793  elog(ERROR, "invalid logtape state: should be dirty");
794  }
795 
796  /*
797  * First allocate the next block, so that we can store it in the
798  * 'next' pointer of this block.
799  */
800  nextBlockNumber = ltsGetPreallocBlock(lts, lt);
801 
802  /* set the next-pointer and dump the current block. */
803  TapeBlockGetTrailer(lt->buffer)->next = nextBlockNumber;
804  ltsWriteBlock(lts, lt->curBlockNumber, (void *) lt->buffer);
805 
806  /* initialize the prev-pointer of the next block */
807  TapeBlockGetTrailer(lt->buffer)->prev = lt->curBlockNumber;
808  lt->curBlockNumber = nextBlockNumber;
809  lt->pos = 0;
810  lt->nbytes = 0;
811  }
812 
813  nthistime = TapeBlockPayloadSize - lt->pos;
814  if (nthistime > size)
815  nthistime = size;
816  Assert(nthistime > 0);
817 
818  memcpy(lt->buffer + lt->pos, ptr, nthistime);
819 
820  lt->dirty = true;
821  lt->pos += nthistime;
822  if (lt->nbytes < lt->pos)
823  lt->nbytes = lt->pos;
824  ptr = (void *) ((char *) ptr + nthistime);
825  size -= nthistime;
826  }
827 }
#define TapeBlockPayloadSize
Definition: logtape.c:102
long offsetBlockNumber
Definition: logtape.c:156
bool writing
Definition: logtape.c:138
bool dirty
Definition: logtape.c:140
#define ERROR
Definition: elog.h:43
int nbytes
Definition: logtape.c:165
long firstBlockNumber
Definition: logtape.c:153
static long ltsGetPreallocBlock(LogicalTapeSet *lts, LogicalTape *lt)
Definition: logtape.c:427
long curBlockNumber
Definition: logtape.c:154
#define Assert(condition)
Definition: c.h:738
LogicalTape * tapes
Definition: logtape.c:216
char * buffer
Definition: logtape.c:161
void * palloc(Size size)
Definition: mcxt.c:949
#define elog(elevel,...)
Definition: elog.h:214
int buffer_size
Definition: logtape.c:162
static void ltsWriteBlock(LogicalTapeSet *lts, long blocknum, void *buffer)
Definition: logtape.c:236
#define TapeBlockGetTrailer(buf)
Definition: logtape.c:103

◆ ltsConcatWorkerTapes()

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

Definition at line 522 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().

524 {
525  LogicalTape *lt = NULL;
526  long tapeblocks = 0L;
527  long nphysicalblocks = 0L;
528  int i;
529 
530  /* Should have at least one worker tape, plus leader's tape */
531  Assert(lts->nTapes >= 2);
532 
533  /*
534  * Build concatenated view of all BufFiles, remembering the block number
535  * where each source file begins. No changes are needed for leader/last
536  * tape.
537  */
538  for (i = 0; i < lts->nTapes - 1; i++)
539  {
540  char filename[MAXPGPATH];
541  BufFile *file;
542  int64 filesize;
543 
544  lt = &lts->tapes[i];
545 
546  pg_itoa(i, filename);
547  file = BufFileOpenShared(fileset, filename);
548  filesize = BufFileSize(file);
549 
550  /*
551  * Stash first BufFile, and concatenate subsequent BufFiles to that.
552  * Store block offset into each tape as we go.
553  */
554  lt->firstBlockNumber = shared[i].firstblocknumber;
555  if (i == 0)
556  {
557  lts->pfile = file;
558  lt->offsetBlockNumber = 0L;
559  }
560  else
561  {
562  lt->offsetBlockNumber = BufFileAppend(lts->pfile, file);
563  }
564  /* Don't allocate more for read buffer than could possibly help */
565  lt->max_size = Min(MaxAllocSize, filesize);
566  tapeblocks = filesize / BLCKSZ;
567  nphysicalblocks += tapeblocks;
568  }
569 
570  /*
571  * Set # of allocated blocks, as well as # blocks written. Use extent of
572  * new BufFile space (from 0 to end of last worker's tape space) for this.
573  * Allocated/written blocks should include space used by holes left
574  * between concatenated BufFiles.
575  */
576  lts->nBlocksAllocated = lt->offsetBlockNumber + tapeblocks;
577  lts->nBlocksWritten = lts->nBlocksAllocated;
578 
579  /*
580  * Compute number of hole blocks so that we can later work backwards, and
581  * instrument number of physical blocks. We don't simply use physical
582  * blocks directly for instrumentation because this would break if we ever
583  * subsequently wrote to the leader tape.
584  *
585  * Working backwards like this keeps our options open. If shared BufFiles
586  * ever support being written to post-export, logtape.c can automatically
587  * take advantage of that. We'd then support writing to the leader tape
588  * while recycling space from worker tapes, because the leader tape has a
589  * zero offset (write routines won't need to have extra logic to apply an
590  * offset).
591  *
592  * The only thing that currently prevents writing to the leader tape from
593  * working is the fact that BufFiles opened using BufFileOpenShared() are
594  * read-only by definition, but that could be changed if it seemed
595  * worthwhile. For now, writing to the leader tape will raise a "Bad file
596  * descriptor" error, so tuplesort must avoid writing to the leader tape
597  * altogether.
598  */
599  lts->nHoleBlocks = lts->nBlocksAllocated - nphysicalblocks;
600 }
int max_size
Definition: logtape.c:163
long offsetBlockNumber
Definition: logtape.c:156
long nBlocksWritten
Definition: logtape.c:198
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:920
BufFile * pfile
Definition: logtape.c:185
long firstblocknumber
Definition: logtape.h:50
#define MAXPGPATH
long nHoleBlocks
Definition: logtape.c:199
void pg_itoa(int16 i, char *a)
Definition: numutils.c:337
#define MaxAllocSize
Definition: memutils.h:40
long firstBlockNumber
Definition: logtape.c:153
#define Assert(condition)
Definition: c.h:738
LogicalTape * tapes
Definition: logtape.c:216
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:197

◆ ltsGetFreeBlock()

static long ltsGetFreeBlock ( LogicalTapeSet lts)
static

Definition at line 371 of file logtape.c.

References LogicalTapeSet::freeBlocks, left_offset(), LogicalTapeSet::nBlocksAllocated, LogicalTapeSet::nFreeBlocks, right_offset(), and swap_nodes().

Referenced by ltsGetPreallocBlock().

372 {
373  long *heap = lts->freeBlocks;
374  long blocknum;
375  int heapsize;
376  unsigned long pos;
377 
378  /* freelist empty; allocate a new block */
379  if (lts->nFreeBlocks == 0)
380  return lts->nBlocksAllocated++;
381 
382  if (lts->nFreeBlocks == 1)
383  {
384  lts->nFreeBlocks--;
385  return lts->freeBlocks[0];
386  }
387 
388  /* take top of minheap */
389  blocknum = heap[0];
390 
391  /* replace with end of minheap array */
392  heap[0] = heap[--lts->nFreeBlocks];
393 
394  /* sift down */
395  pos = 0;
396  heapsize = lts->nFreeBlocks;
397  while (true)
398  {
399  unsigned long left = left_offset(pos);
400  unsigned long right = right_offset(pos);
401  unsigned long min_child;
402 
403  if (left < heapsize && right < heapsize)
404  min_child = (heap[left] < heap[right]) ? left : right;
405  else if (left < heapsize)
406  min_child = left;
407  else if (right < heapsize)
408  min_child = right;
409  else
410  break;
411 
412  if (heap[min_child] >= heap[pos])
413  break;
414 
415  swap_nodes(heap, min_child, pos);
416  pos = min_child;
417  }
418 
419  return blocknum;
420 }
static void swap_nodes(long *heap, unsigned long a, unsigned long b)
Definition: logtape.c:339
long * freeBlocks
Definition: logtape.c:210
static unsigned long right_offset(unsigned i)
Definition: logtape.c:355
static unsigned long left_offset(unsigned long i)
Definition: logtape.c:349
long nFreeBlocks
Definition: logtape.c:211
long nBlocksAllocated
Definition: logtape.c:197

◆ ltsGetPreallocBlock()

static long ltsGetPreallocBlock ( LogicalTapeSet lts,
LogicalTape lt 
)
static

Definition at line 427 of file logtape.c.

References Assert, i, ltsGetFreeBlock(), LogicalTape::nprealloc, palloc(), LogicalTape::prealloc, LogicalTape::prealloc_size, repalloc(), TAPE_WRITE_PREALLOC_MAX, and TAPE_WRITE_PREALLOC_MIN.

Referenced by LogicalTapeWrite().

428 {
429  /* sorted in descending order, so return the last element */
430  if (lt->nprealloc > 0)
431  return lt->prealloc[--lt->nprealloc];
432 
433  if (lt->prealloc == NULL)
434  {
436  lt->prealloc = (long *) palloc(sizeof(long) * lt->prealloc_size);
437  }
438  else if (lt->prealloc_size < TAPE_WRITE_PREALLOC_MAX)
439  {
440  /* when the preallocation list runs out, double the size */
441  lt->prealloc_size *= 2;
444  lt->prealloc = (long *) repalloc(lt->prealloc,
445  sizeof(long) * lt->prealloc_size);
446  }
447 
448  /* refill preallocation list */
449  lt->nprealloc = lt->prealloc_size;
450  for (int i = lt->nprealloc; i > 0; i--)
451  {
452  lt->prealloc[i - 1] = ltsGetFreeBlock(lts);
453 
454  /* verify descending order */
455  Assert(i == lt->nprealloc || lt->prealloc[i - 1] > lt->prealloc[i]);
456  }
457 
458  return lt->prealloc[--lt->nprealloc];
459 }
long * prealloc
Definition: logtape.c:172
static long ltsGetFreeBlock(LogicalTapeSet *lts)
Definition: logtape.c:371
int prealloc_size
Definition: logtape.c:174
int nprealloc
Definition: logtape.c:173
#define TAPE_WRITE_PREALLOC_MAX
Definition: logtape.c:124
#define TAPE_WRITE_PREALLOC_MIN
Definition: logtape.c:123
#define Assert(condition)
Definition: c.h:738
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1069
void * palloc(Size size)
Definition: mcxt.c:949
int i

◆ ltsInitReadBuffer()

static void ltsInitReadBuffer ( LogicalTapeSet lts,
LogicalTape lt 
)
static

Definition at line 632 of file logtape.c.

References Assert, LogicalTape::buffer, LogicalTape::buffer_size, LogicalTape::firstBlockNumber, ltsReadFillBuffer(), LogicalTape::nbytes, LogicalTape::nextBlockNumber, palloc(), and LogicalTape::pos.

Referenced by LogicalTapeBackspace(), LogicalTapeRead(), LogicalTapeSeek(), and LogicalTapeTell().

633 {
634  Assert(lt->buffer_size > 0);
635  lt->buffer = palloc(lt->buffer_size);
636 
637  /* Read the first block, or reset if tape is empty */
639  lt->pos = 0;
640  lt->nbytes = 0;
641  ltsReadFillBuffer(lts, lt);
642 }
static bool ltsReadFillBuffer(LogicalTapeSet *lts, LogicalTape *lt)
Definition: logtape.c:300
long nextBlockNumber
Definition: logtape.c:155
int nbytes
Definition: logtape.c:165
long firstBlockNumber
Definition: logtape.c:153
#define Assert(condition)
Definition: c.h:738
char * buffer
Definition: logtape.c:161
void * palloc(Size size)
Definition: mcxt.c:949
int buffer_size
Definition: logtape.c:162

◆ ltsInitTape()

static void ltsInitTape ( LogicalTape lt)
static

Definition at line 606 of file logtape.c.

References LogicalTape::buffer, LogicalTape::buffer_size, LogicalTape::curBlockNumber, LogicalTape::dirty, LogicalTape::firstBlockNumber, LogicalTape::frozen, LogicalTape::max_size, MaxAllocSize, LogicalTape::nbytes, LogicalTape::nextBlockNumber, LogicalTape::nprealloc, LogicalTape::offsetBlockNumber, LogicalTape::pos, LogicalTape::prealloc, LogicalTape::prealloc_size, and LogicalTape::writing.

Referenced by LogicalTapeSetCreate(), and LogicalTapeSetExtend().

607 {
608  lt->writing = true;
609  lt->frozen = false;
610  lt->dirty = false;
611  lt->firstBlockNumber = -1L;
612  lt->curBlockNumber = -1L;
613  lt->nextBlockNumber = -1L;
614  lt->offsetBlockNumber = 0L;
615  lt->buffer = NULL;
616  lt->buffer_size = 0;
617  /* palloc() larger than MaxAllocSize would fail */
618  lt->max_size = MaxAllocSize;
619  lt->pos = 0;
620  lt->nbytes = 0;
621  lt->prealloc = NULL;
622  lt->nprealloc = 0;
623  lt->prealloc_size = 0;
624 }
int max_size
Definition: logtape.c:163
long offsetBlockNumber
Definition: logtape.c:156
long * prealloc
Definition: logtape.c:172
int prealloc_size
Definition: logtape.c:174
bool frozen
Definition: logtape.c:139
long nextBlockNumber
Definition: logtape.c:155
bool writing
Definition: logtape.c:138
bool dirty
Definition: logtape.c:140
int nbytes
Definition: logtape.c:165
int nprealloc
Definition: logtape.c:173
#define MaxAllocSize
Definition: memutils.h:40
long firstBlockNumber
Definition: logtape.c:153
long curBlockNumber
Definition: logtape.c:154
char * buffer
Definition: logtape.c:161
int buffer_size
Definition: logtape.c:162

◆ ltsReadBlock()

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

Definition at line 284 of file logtape.c.

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

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

285 {
286  if (BufFileSeekBlock(lts->pfile, blocknum) != 0 ||
287  BufFileRead(lts->pfile, buffer, BLCKSZ) != BLCKSZ)
288  ereport(ERROR,
290  errmsg("could not read block %ld of temporary file: %m",
291  blocknum)));
292 }
BufFile * pfile
Definition: logtape.c:185
#define ERROR
Definition: elog.h:43
int errcode_for_file_access(void)
Definition: elog.c:633
int BufFileSeekBlock(BufFile *file, long blknum)
Definition: buffile.c:752
#define ereport(elevel,...)
Definition: elog.h:144
int errmsg(const char *fmt,...)
Definition: elog.c:824
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 300 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 ltsInitReadBuffer().

301 {
302  lt->pos = 0;
303  lt->nbytes = 0;
304 
305  do
306  {
307  char *thisbuf = lt->buffer + lt->nbytes;
308  long datablocknum = lt->nextBlockNumber;
309 
310  /* Fetch next block number */
311  if (datablocknum == -1L)
312  break; /* EOF */
313  /* Apply worker offset, needed for leader tapesets */
314  datablocknum += lt->offsetBlockNumber;
315 
316  /* Read the block */
317  ltsReadBlock(lts, datablocknum, (void *) thisbuf);
318  if (!lt->frozen)
319  ltsReleaseBlock(lts, datablocknum);
321 
322  lt->nbytes += TapeBlockGetNBytes(thisbuf);
323  if (TapeBlockIsLast(thisbuf))
324  {
325  lt->nextBlockNumber = -1L;
326  /* EOF */
327  break;
328  }
329  else
330  lt->nextBlockNumber = TapeBlockGetTrailer(thisbuf)->next;
331 
332  /* Advance to next block, if we have buffer space left */
333  } while (lt->buffer_size - lt->nbytes > BLCKSZ);
334 
335  return (lt->nbytes > 0);
336 }
#define TapeBlockIsLast(buf)
Definition: logtape.c:106
long offsetBlockNumber
Definition: logtape.c:156
static void ltsReleaseBlock(LogicalTapeSet *lts, long blocknum)
Definition: logtape.c:465
bool frozen
Definition: logtape.c:139
long nextBlockNumber
Definition: logtape.c:155
int nbytes
Definition: logtape.c:165
long curBlockNumber
Definition: logtape.c:154
#define TapeBlockGetNBytes(buf)
Definition: logtape.c:107
char * buffer
Definition: logtape.c:161
int buffer_size
Definition: logtape.c:162
#define TapeBlockGetTrailer(buf)
Definition: logtape.c:103
static void ltsReadBlock(LogicalTapeSet *lts, long blocknum, void *buffer)
Definition: logtape.c:284

◆ ltsReleaseBlock()

static void ltsReleaseBlock ( LogicalTapeSet lts,
long  blocknum 
)
static

Definition at line 465 of file logtape.c.

References LogicalTapeSet::forgetFreeSpace, LogicalTapeSet::freeBlocks, LogicalTapeSet::freeBlocksLen, MaxAllocSize, LogicalTapeSet::nFreeBlocks, parent_offset(), repalloc(), and swap_nodes().

Referenced by LogicalTapeRewindForRead(), and ltsReadFillBuffer().

466 {
467  long *heap;
468  unsigned long pos;
469 
470  /*
471  * Do nothing if we're no longer interested in remembering free space.
472  */
473  if (lts->forgetFreeSpace)
474  return;
475 
476  /*
477  * Enlarge freeBlocks array if full.
478  */
479  if (lts->nFreeBlocks >= lts->freeBlocksLen)
480  {
481  /*
482  * If the freelist becomes very large, just return and leak this free
483  * block.
484  */
485  if (lts->freeBlocksLen * 2 > MaxAllocSize)
486  return;
487 
488  lts->freeBlocksLen *= 2;
489  lts->freeBlocks = (long *) repalloc(lts->freeBlocks,
490  lts->freeBlocksLen * sizeof(long));
491  }
492 
493  heap = lts->freeBlocks;
494  pos = lts->nFreeBlocks;
495 
496  /* place entry at end of minheap array */
497  heap[pos] = blocknum;
498  lts->nFreeBlocks++;
499 
500  /* sift up */
501  while (pos != 0)
502  {
503  unsigned long parent = parent_offset(pos);
504 
505  if (heap[parent] < heap[pos])
506  break;
507 
508  swap_nodes(heap, parent, pos);
509  pos = parent;
510  }
511 }
static void swap_nodes(long *heap, unsigned long a, unsigned long b)
Definition: logtape.c:339
long * freeBlocks
Definition: logtape.c:210
#define MaxAllocSize
Definition: memutils.h:40
long nFreeBlocks
Definition: logtape.c:211
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1069
bool forgetFreeSpace
Definition: logtape.c:209
Size freeBlocksLen
Definition: logtape.c:212
static unsigned long parent_offset(unsigned long i)
Definition: logtape.c:361

◆ ltsWriteBlock()

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

Definition at line 236 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().

237 {
238  /*
239  * BufFile does not support "holes", so if we're about to write a block
240  * that's past the current end of file, fill the space between the current
241  * end of file and the target block with zeros.
242  *
243  * This should happen rarely, otherwise you are not writing very
244  * sequentially. In current use, this only happens when the sort ends
245  * writing a run, and switches to another tape. The last block of the
246  * previous tape isn't flushed to disk until the end of the sort, so you
247  * get one-block hole, where the last block of the previous tape will
248  * later go.
249  *
250  * Note that BufFile concatenation can leave "holes" in BufFile between
251  * worker-owned block ranges. These are tracked for reporting purposes
252  * only. We never read from nor write to these hole blocks, and so they
253  * are not considered here.
254  */
255  while (blocknum > lts->nBlocksWritten)
256  {
257  PGAlignedBlock zerobuf;
258 
259  MemSet(zerobuf.data, 0, sizeof(zerobuf));
260 
261  ltsWriteBlock(lts, lts->nBlocksWritten, zerobuf.data);
262  }
263 
264  /* Write the requested block */
265  if (BufFileSeekBlock(lts->pfile, blocknum) != 0 ||
266  BufFileWrite(lts->pfile, buffer, BLCKSZ) != BLCKSZ)
267  ereport(ERROR,
269  errmsg("could not write block %ld of temporary file: %m",
270  blocknum)));
271 
272  /* Update nBlocksWritten, if we extended the file */
273  if (blocknum == lts->nBlocksWritten)
274  lts->nBlocksWritten++;
275 }
long nBlocksWritten
Definition: logtape.c:198
BufFile * pfile
Definition: logtape.c:185
#define MemSet(start, val, len)
Definition: c.h:971
char data[BLCKSZ]
Definition: c.h:1104
#define ERROR
Definition: elog.h:43
int errcode_for_file_access(void)
Definition: elog.c:633
int BufFileSeekBlock(BufFile *file, long blknum)
Definition: buffile.c:752
#define ereport(elevel,...)
Definition: elog.h:144
int errmsg(const char *fmt,...)
Definition: elog.c:824
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:236

◆ parent_offset()

static unsigned long parent_offset ( unsigned long  i)
inlinestatic

Definition at line 361 of file logtape.c.

Referenced by ltsReleaseBlock().

362 {
363  return (i - 1) / 2;
364 }
int i

◆ right_offset()

static unsigned long right_offset ( unsigned  i)
inlinestatic

Definition at line 355 of file logtape.c.

Referenced by ltsGetFreeBlock().

356 {
357  return 2 * i + 2;
358 }
int i

◆ swap_nodes()

static void swap_nodes ( long *  heap,
unsigned long  a,
unsigned long  b 
)
inlinestatic

Definition at line 339 of file logtape.c.

References swap.

Referenced by ltsGetFreeBlock(), and ltsReleaseBlock().

340 {
341  unsigned long swap;
342 
343  swap = heap[a];
344  heap[a] = heap[b];
345  heap[b] = swap;
346 }
#define swap(a, b)
Definition: qsort.c:94