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 356 of file logtape.c.

Referenced by ltsGetFreeBlock().

357 {
358  return 2 * i + 1;
359 }
int i

◆ LogicalTapeBackspace()

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

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

1124 {
1125  LogicalTape *lt;
1126  size_t seekpos = 0;
1127 
1128  Assert(tapenum >= 0 && tapenum < lts->nTapes);
1129  lt = &lts->tapes[tapenum];
1130  Assert(lt->frozen);
1131  Assert(lt->buffer_size == BLCKSZ);
1132 
1133  if (lt->buffer == NULL)
1134  ltsInitReadBuffer(lts, lt);
1135 
1136  /*
1137  * Easy case for seek within current block.
1138  */
1139  if (size <= (size_t) lt->pos)
1140  {
1141  lt->pos -= (int) size;
1142  return size;
1143  }
1144 
1145  /*
1146  * Not-so-easy case, have to walk back the chain of blocks. This
1147  * implementation would be pretty inefficient for long seeks, but we
1148  * really aren't doing that (a seek over one tuple is typical).
1149  */
1150  seekpos = (size_t) lt->pos; /* part within this block */
1151  while (size > seekpos)
1152  {
1153  long prev = TapeBlockGetTrailer(lt->buffer)->prev;
1154 
1155  if (prev == -1L)
1156  {
1157  /* Tried to back up beyond the beginning of tape. */
1158  if (lt->curBlockNumber != lt->firstBlockNumber)
1159  elog(ERROR, "unexpected end of tape");
1160  lt->pos = 0;
1161  return seekpos;
1162  }
1163 
1164  ltsReadBlock(lts, prev, (void *) lt->buffer);
1165 
1166  if (TapeBlockGetTrailer(lt->buffer)->next != lt->curBlockNumber)
1167  elog(ERROR, "broken tape, next of block %ld is %ld, expected %ld",
1168  prev,
1169  TapeBlockGetTrailer(lt->buffer)->next,
1170  lt->curBlockNumber);
1171 
1173  lt->curBlockNumber = prev;
1174  lt->nextBlockNumber = TapeBlockGetTrailer(lt->buffer)->next;
1175 
1176  seekpos += TapeBlockPayloadSize;
1177  }
1178 
1179  /*
1180  * 'seekpos' can now be greater than 'size', because it points to the
1181  * beginning the target block. The difference is the position within the
1182  * page.
1183  */
1184  lt->pos = seekpos - size;
1185  return size;
1186 }
#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:639
long curBlockNumber
Definition: logtape.c:154
#define Assert(condition)
Definition: c.h:745
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 1020 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().

1021 {
1022  LogicalTape *lt;
1023 
1024  Assert(tapenum >= 0 && tapenum < lts->nTapes);
1025  lt = &lts->tapes[tapenum];
1026  Assert(lt->writing);
1027  Assert(lt->offsetBlockNumber == 0L);
1028 
1029  /*
1030  * Completion of a write phase. Flush last partial data block, and rewind
1031  * for nondestructive read.
1032  */
1033  if (lt->dirty)
1034  {
1035  /*
1036  * As long as we've filled the buffer at least once, its contents are
1037  * entirely defined from valgrind's point of view, even though
1038  * contents beyond the current end point may be stale. But it's
1039  * possible - at least in the case of a parallel sort - to sort such
1040  * small amount of data that we do not fill the buffer even once. Tell
1041  * valgrind that its contents are defined, so it doesn't bleat.
1042  */
1044  lt->buffer_size - lt->nbytes);
1045 
1046  TapeBlockSetNBytes(lt->buffer, lt->nbytes);
1047  ltsWriteBlock(lts, lt->curBlockNumber, (void *) lt->buffer);
1048  lt->writing = false;
1049  }
1050  lt->writing = false;
1051  lt->frozen = true;
1052 
1053  /*
1054  * The seek and backspace functions assume a single block read buffer.
1055  * That's OK with current usage. A larger buffer is helpful to make the
1056  * read pattern of the backing file look more sequential to the OS, when
1057  * we're reading from multiple tapes. But at the end of a sort, when a
1058  * tape is frozen, we only read from a single tape anyway.
1059  */
1060  if (!lt->buffer || lt->buffer_size != BLCKSZ)
1061  {
1062  if (lt->buffer)
1063  pfree(lt->buffer);
1064  lt->buffer = palloc(BLCKSZ);
1065  lt->buffer_size = BLCKSZ;
1066  }
1067 
1068  /* Read the first block, or reset if tape is empty */
1069  lt->curBlockNumber = lt->firstBlockNumber;
1070  lt->pos = 0;
1071  lt->nbytes = 0;
1072 
1073  if (lt->firstBlockNumber == -1L)
1074  lt->nextBlockNumber = -1L;
1075  ltsReadBlock(lts, lt->curBlockNumber, (void *) lt->buffer);
1076  if (TapeBlockIsLast(lt->buffer))
1077  lt->nextBlockNumber = -1L;
1078  else
1079  lt->nextBlockNumber = TapeBlockGetTrailer(lt->buffer)->next;
1080  lt->nbytes = TapeBlockGetNBytes(lt->buffer);
1081 
1082  /* Handle extra steps when caller is to share its tapeset */
1083  if (share)
1084  {
1085  BufFileExportShared(lts->pfile);
1086  share->firstblocknumber = lt->firstBlockNumber;
1087  }
1088 }
#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:745
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 963 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().

965 {
966  LogicalTape *lt;
967  size_t nread = 0;
968  size_t nthistime;
969 
970  Assert(tapenum >= 0 && tapenum < lts->nTapes);
971  lt = &lts->tapes[tapenum];
972  Assert(!lt->writing);
973 
974  if (lt->buffer == NULL)
975  ltsInitReadBuffer(lts, lt);
976 
977  while (size > 0)
978  {
979  if (lt->pos >= lt->nbytes)
980  {
981  /* Try to load more data into buffer. */
982  if (!ltsReadFillBuffer(lts, lt))
983  break; /* EOF */
984  }
985 
986  nthistime = lt->nbytes - lt->pos;
987  if (nthistime > size)
988  nthistime = size;
989  Assert(nthistime > 0);
990 
991  memcpy(ptr, lt->buffer + lt->pos, nthistime);
992 
993  lt->pos += nthistime;
994  ptr = (void *) ((char *) ptr + nthistime);
995  size -= nthistime;
996  nread += nthistime;
997  }
998 
999  return nread;
1000 }
static bool ltsReadFillBuffer(LogicalTapeSet *lts, LogicalTape *lt)
Definition: logtape.c:307
bool writing
Definition: logtape.c:138
int nbytes
Definition: logtape.c:165
static void ltsInitReadBuffer(LogicalTapeSet *lts, LogicalTape *lt)
Definition: logtape.c:639
#define Assert(condition)
Definition: c.h:745
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 849 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().

850 {
851  LogicalTape *lt;
852 
853  Assert(tapenum >= 0 && tapenum < lts->nTapes);
854  lt = &lts->tapes[tapenum];
855 
856  /*
857  * Round and cap buffer_size if needed.
858  */
859  if (lt->frozen)
860  buffer_size = BLCKSZ;
861  else
862  {
863  /* need at least one block */
864  if (buffer_size < BLCKSZ)
865  buffer_size = BLCKSZ;
866 
867  /* palloc() larger than max_size is unlikely to be helpful */
868  if (buffer_size > lt->max_size)
869  buffer_size = lt->max_size;
870 
871  /* round down to BLCKSZ boundary */
872  buffer_size -= buffer_size % BLCKSZ;
873  }
874 
875  if (lt->writing)
876  {
877  /*
878  * Completion of a write phase. Flush last partial data block, and
879  * rewind for normal (destructive) read.
880  */
881  if (lt->dirty)
882  {
883  /*
884  * As long as we've filled the buffer at least once, its contents
885  * are entirely defined from valgrind's point of view, even though
886  * contents beyond the current end point may be stale. But it's
887  * possible - at least in the case of a parallel sort - to sort
888  * such small amount of data that we do not fill the buffer even
889  * once. Tell valgrind that its contents are defined, so it
890  * doesn't bleat.
891  */
893  lt->buffer_size - lt->nbytes);
894 
895  TapeBlockSetNBytes(lt->buffer, lt->nbytes);
896  ltsWriteBlock(lts, lt->curBlockNumber, (void *) lt->buffer);
897  }
898  lt->writing = false;
899  }
900  else
901  {
902  /*
903  * This is only OK if tape is frozen; we rewind for (another) read
904  * pass.
905  */
906  Assert(lt->frozen);
907  }
908 
909  if (lt->buffer)
910  pfree(lt->buffer);
911 
912  /* the buffer is lazily allocated, but set the size here */
913  lt->buffer = NULL;
914  lt->buffer_size = buffer_size;
915 
916  /* free the preallocation list, and return unused block numbers */
917  if (lt->prealloc != NULL)
918  {
919  for (int i = lt->nprealloc; i > 0; i--)
920  ltsReleaseBlock(lts, lt->prealloc[i - 1]);
921  pfree(lt->prealloc);
922  lt->prealloc = NULL;
923  lt->nprealloc = 0;
924  lt->prealloc_size = 0;
925  }
926 }
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:472
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:745
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 937 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().

938 {
939  LogicalTape *lt;
940 
941  Assert(tapenum >= 0 && tapenum < lts->nTapes);
942  lt = &lts->tapes[tapenum];
943 
944  Assert(!lt->writing && !lt->frozen);
945  lt->writing = true;
946  lt->dirty = false;
947  lt->firstBlockNumber = -1L;
948  lt->curBlockNumber = -1L;
949  lt->pos = 0;
950  lt->nbytes = 0;
951  if (lt->buffer)
952  pfree(lt->buffer);
953  lt->buffer = NULL;
954  lt->buffer_size = 0;
955 }
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:745
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 1197 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().

1199 {
1200  LogicalTape *lt;
1201 
1202  Assert(tapenum >= 0 && tapenum < lts->nTapes);
1203  lt = &lts->tapes[tapenum];
1204  Assert(lt->frozen);
1205  Assert(offset >= 0 && offset <= TapeBlockPayloadSize);
1206  Assert(lt->buffer_size == BLCKSZ);
1207 
1208  if (lt->buffer == NULL)
1209  ltsInitReadBuffer(lts, lt);
1210 
1211  if (blocknum != lt->curBlockNumber)
1212  {
1213  ltsReadBlock(lts, blocknum, (void *) lt->buffer);
1214  lt->curBlockNumber = blocknum;
1216  lt->nextBlockNumber = TapeBlockGetTrailer(lt->buffer)->next;
1217  }
1218 
1219  if (offset > lt->nbytes)
1220  elog(ERROR, "invalid tape seek position");
1221  lt->pos = offset;
1222 }
#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:639
long curBlockNumber
Definition: logtape.c:154
#define Assert(condition)
Definition: c.h:745
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 1255 of file logtape.c.

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

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

1256 {
1257  return lts->nBlocksAllocated - lts->nHoleBlocks;
1258 }
long nHoleBlocks
Definition: logtape.c:199
long nBlocksAllocated
Definition: logtape.c:197

◆ LogicalTapeSetClose()

void LogicalTapeSetClose ( LogicalTapeSet lts)

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

724 {
725  LogicalTape *lt;
726  int i;
727 
728  BufFileClose(lts->pfile);
729  for (i = 0; i < lts->nTapes; i++)
730  {
731  lt = &lts->tapes[i];
732  if (lt->buffer)
733  pfree(lt->buffer);
734  }
735  pfree(lts->tapes);
736  pfree(lts->freeBlocks);
737  pfree(lts);
738 }
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 672 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().

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

◆ LogicalTapeSetExtend()

void LogicalTapeSetExtend ( LogicalTapeSet lts,
int  nAdditional 
)

Definition at line 1095 of file logtape.c.

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

Referenced by hashagg_tapeinfo_assign().

1096 {
1097  int i;
1098  int nTapesOrig = lts->nTapes;
1099 
1100  lts->nTapes += nAdditional;
1101 
1102  lts->tapes = (LogicalTape *) repalloc(lts->tapes,
1103  lts->nTapes * sizeof(LogicalTape));
1104 
1105  for (i = nTapesOrig; i < lts->nTapes; i++)
1106  ltsInitTape(&lts->tapes[i]);
1107 }
static void ltsInitTape(LogicalTape *lt)
Definition: logtape.c:613
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 750 of file logtape.c.

References LogicalTapeSet::forgetFreeSpace.

Referenced by mergeruns().

751 {
752  lts->forgetFreeSpace = true;
753 }
bool forgetFreeSpace
Definition: logtape.c:209

◆ LogicalTapeTell()

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

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

1233 {
1234  LogicalTape *lt;
1235 
1236  Assert(tapenum >= 0 && tapenum < lts->nTapes);
1237  lt = &lts->tapes[tapenum];
1238 
1239  if (lt->buffer == NULL)
1240  ltsInitReadBuffer(lts, lt);
1241 
1242  Assert(lt->offsetBlockNumber == 0L);
1243 
1244  /* With a larger buffer, 'pos' wouldn't be the same as offset within page */
1245  Assert(lt->buffer_size == BLCKSZ);
1246 
1247  *blocknum = lt->curBlockNumber;
1248  *offset = lt->pos;
1249 }
long offsetBlockNumber
Definition: logtape.c:156
static void ltsInitReadBuffer(LogicalTapeSet *lts, LogicalTape *lt)
Definition: logtape.c:639
long curBlockNumber
Definition: logtape.c:154
#define Assert(condition)
Definition: c.h:745
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 761 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().

763 {
764  LogicalTape *lt;
765  size_t nthistime;
766 
767  Assert(tapenum >= 0 && tapenum < lts->nTapes);
768  lt = &lts->tapes[tapenum];
769  Assert(lt->writing);
770  Assert(lt->offsetBlockNumber == 0L);
771 
772  /* Allocate data buffer and first block on first write */
773  if (lt->buffer == NULL)
774  {
775  lt->buffer = (char *) palloc(BLCKSZ);
776  lt->buffer_size = BLCKSZ;
777  }
778  if (lt->curBlockNumber == -1)
779  {
780  Assert(lt->firstBlockNumber == -1);
781  Assert(lt->pos == 0);
782 
783  lt->curBlockNumber = ltsGetPreallocBlock(lts, lt);
785 
786  TapeBlockGetTrailer(lt->buffer)->prev = -1L;
787  }
788 
789  Assert(lt->buffer_size == BLCKSZ);
790  while (size > 0)
791  {
792  if (lt->pos >= (int) TapeBlockPayloadSize)
793  {
794  /* Buffer full, dump it out */
795  long nextBlockNumber;
796 
797  if (!lt->dirty)
798  {
799  /* Hmm, went directly from reading to writing? */
800  elog(ERROR, "invalid logtape state: should be dirty");
801  }
802 
803  /*
804  * First allocate the next block, so that we can store it in the
805  * 'next' pointer of this block.
806  */
807  nextBlockNumber = ltsGetPreallocBlock(lts, lt);
808 
809  /* set the next-pointer and dump the current block. */
810  TapeBlockGetTrailer(lt->buffer)->next = nextBlockNumber;
811  ltsWriteBlock(lts, lt->curBlockNumber, (void *) lt->buffer);
812 
813  /* initialize the prev-pointer of the next block */
814  TapeBlockGetTrailer(lt->buffer)->prev = lt->curBlockNumber;
815  lt->curBlockNumber = nextBlockNumber;
816  lt->pos = 0;
817  lt->nbytes = 0;
818  }
819 
820  nthistime = TapeBlockPayloadSize - lt->pos;
821  if (nthistime > size)
822  nthistime = size;
823  Assert(nthistime > 0);
824 
825  memcpy(lt->buffer + lt->pos, ptr, nthistime);
826 
827  lt->dirty = true;
828  lt->pos += nthistime;
829  if (lt->nbytes < lt->pos)
830  lt->nbytes = lt->pos;
831  ptr = (void *) ((char *) ptr + nthistime);
832  size -= nthistime;
833  }
834 }
#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:434
long curBlockNumber
Definition: logtape.c:154
#define Assert(condition)
Definition: c.h:745
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 529 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().

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

◆ ltsGetFreeBlock()

static long ltsGetFreeBlock ( LogicalTapeSet lts)
static

Definition at line 378 of file logtape.c.

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

Referenced by ltsGetPreallocBlock().

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

◆ ltsGetPreallocBlock()

static long ltsGetPreallocBlock ( LogicalTapeSet lts,
LogicalTape lt 
)
static

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

435 {
436  /* sorted in descending order, so return the last element */
437  if (lt->nprealloc > 0)
438  return lt->prealloc[--lt->nprealloc];
439 
440  if (lt->prealloc == NULL)
441  {
443  lt->prealloc = (long *) palloc(sizeof(long) * lt->prealloc_size);
444  }
445  else if (lt->prealloc_size < TAPE_WRITE_PREALLOC_MAX)
446  {
447  /* when the preallocation list runs out, double the size */
448  lt->prealloc_size *= 2;
451  lt->prealloc = (long *) repalloc(lt->prealloc,
452  sizeof(long) * lt->prealloc_size);
453  }
454 
455  /* refill preallocation list */
456  lt->nprealloc = lt->prealloc_size;
457  for (int i = lt->nprealloc; i > 0; i--)
458  {
459  lt->prealloc[i - 1] = ltsGetFreeBlock(lts);
460 
461  /* verify descending order */
462  Assert(i == lt->nprealloc || lt->prealloc[i - 1] > lt->prealloc[i]);
463  }
464 
465  return lt->prealloc[--lt->nprealloc];
466 }
long * prealloc
Definition: logtape.c:172
static long ltsGetFreeBlock(LogicalTapeSet *lts)
Definition: logtape.c:378
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:745
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 639 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().

640 {
641  Assert(lt->buffer_size > 0);
642  lt->buffer = palloc(lt->buffer_size);
643 
644  /* Read the first block, or reset if tape is empty */
646  lt->pos = 0;
647  lt->nbytes = 0;
648  ltsReadFillBuffer(lts, lt);
649 }
static bool ltsReadFillBuffer(LogicalTapeSet *lts, LogicalTape *lt)
Definition: logtape.c:307
long nextBlockNumber
Definition: logtape.c:155
int nbytes
Definition: logtape.c:165
long firstBlockNumber
Definition: logtape.c:153
#define Assert(condition)
Definition: c.h:745
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 613 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().

614 {
615  lt->writing = true;
616  lt->frozen = false;
617  lt->dirty = false;
618  lt->firstBlockNumber = -1L;
619  lt->curBlockNumber = -1L;
620  lt->nextBlockNumber = -1L;
621  lt->offsetBlockNumber = 0L;
622  lt->buffer = NULL;
623  lt->buffer_size = 0;
624  /* palloc() larger than MaxAllocSize would fail */
625  lt->max_size = MaxAllocSize;
626  lt->pos = 0;
627  lt->nbytes = 0;
628  lt->prealloc = NULL;
629  lt->nprealloc = 0;
630  lt->prealloc_size = 0;
631 }
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  size_t nread;
287 
288  if (BufFileSeekBlock(lts->pfile, blocknum) != 0)
289  ereport(ERROR,
291  errmsg("could not seek to block %ld of temporary file",
292  blocknum)));
293  nread = BufFileRead(lts->pfile, buffer, BLCKSZ);
294  if (nread != BLCKSZ)
295  ereport(ERROR,
297  errmsg("could not read block %ld of temporary file: read only %zu of %zu bytes",
298  blocknum, nread, (size_t) BLCKSZ)));
299 }
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:747
#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:539

◆ ltsReadFillBuffer()

static bool ltsReadFillBuffer ( LogicalTapeSet lts,
LogicalTape lt 
)
static

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

308 {
309  lt->pos = 0;
310  lt->nbytes = 0;
311 
312  do
313  {
314  char *thisbuf = lt->buffer + lt->nbytes;
315  long datablocknum = lt->nextBlockNumber;
316 
317  /* Fetch next block number */
318  if (datablocknum == -1L)
319  break; /* EOF */
320  /* Apply worker offset, needed for leader tapesets */
321  datablocknum += lt->offsetBlockNumber;
322 
323  /* Read the block */
324  ltsReadBlock(lts, datablocknum, (void *) thisbuf);
325  if (!lt->frozen)
326  ltsReleaseBlock(lts, datablocknum);
328 
329  lt->nbytes += TapeBlockGetNBytes(thisbuf);
330  if (TapeBlockIsLast(thisbuf))
331  {
332  lt->nextBlockNumber = -1L;
333  /* EOF */
334  break;
335  }
336  else
337  lt->nextBlockNumber = TapeBlockGetTrailer(thisbuf)->next;
338 
339  /* Advance to next block, if we have buffer space left */
340  } while (lt->buffer_size - lt->nbytes > BLCKSZ);
341 
342  return (lt->nbytes > 0);
343 }
#define TapeBlockIsLast(buf)
Definition: logtape.c:106
long offsetBlockNumber
Definition: logtape.c:156
static void ltsReleaseBlock(LogicalTapeSet *lts, long blocknum)
Definition: logtape.c:472
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 472 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().

473 {
474  long *heap;
475  unsigned long pos;
476 
477  /*
478  * Do nothing if we're no longer interested in remembering free space.
479  */
480  if (lts->forgetFreeSpace)
481  return;
482 
483  /*
484  * Enlarge freeBlocks array if full.
485  */
486  if (lts->nFreeBlocks >= lts->freeBlocksLen)
487  {
488  /*
489  * If the freelist becomes very large, just return and leak this free
490  * block.
491  */
492  if (lts->freeBlocksLen * 2 > MaxAllocSize)
493  return;
494 
495  lts->freeBlocksLen *= 2;
496  lts->freeBlocks = (long *) repalloc(lts->freeBlocks,
497  lts->freeBlocksLen * sizeof(long));
498  }
499 
500  heap = lts->freeBlocks;
501  pos = lts->nFreeBlocks;
502 
503  /* place entry at end of minheap array */
504  heap[pos] = blocknum;
505  lts->nFreeBlocks++;
506 
507  /* sift up */
508  while (pos != 0)
509  {
510  unsigned long parent = parent_offset(pos);
511 
512  if (heap[parent] < heap[pos])
513  break;
514 
515  swap_nodes(heap, parent, pos);
516  pos = parent;
517  }
518 }
static void swap_nodes(long *heap, unsigned long a, unsigned long b)
Definition: logtape.c:346
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:368

◆ 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  ereport(ERROR,
268  errmsg("could not seek to block %ld of temporary file",
269  blocknum)));
270  BufFileWrite(lts->pfile, buffer, BLCKSZ);
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:978
char data[BLCKSZ]
Definition: c.h:1111
#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:747
#define ereport(elevel,...)
Definition: elog.h:144
int errmsg(const char *fmt,...)
Definition: elog.c:824
void BufFileWrite(BufFile *file, void *ptr, size_t size)
Definition: buffile.c:582
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 368 of file logtape.c.

Referenced by ltsReleaseBlock().

369 {
370  return (i - 1) / 2;
371 }
int i

◆ right_offset()

static unsigned long right_offset ( unsigned  i)
inlinestatic

Definition at line 362 of file logtape.c.

Referenced by ltsGetFreeBlock().

363 {
364  return 2 * i + 2;
365 }
int i

◆ swap_nodes()

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

Definition at line 346 of file logtape.c.

References swap.

Referenced by ltsGetFreeBlock(), and ltsReleaseBlock().

347 {
348  unsigned long swap;
349 
350  swap = heap[a];
351  heap[a] = heap[b];
352  heap[b] = swap;
353 }
#define swap(a, b)
Definition: qsort.c:94