PostgreSQL Source Code  git master
logtape.h File Reference
Include dependency graph for logtape.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  TapeShare
 

Typedefs

typedef struct LogicalTapeSet LogicalTapeSet
 
typedef struct LogicalTape LogicalTape
 
typedef struct TapeShare TapeShare
 

Functions

LogicalTapeSetLogicalTapeSetCreate (bool preallocate, SharedFileSet *fileset, int worker)
 
void LogicalTapeClose (LogicalTape *lt)
 
void LogicalTapeSetClose (LogicalTapeSet *lts)
 
LogicalTapeLogicalTapeCreate (LogicalTapeSet *lts)
 
LogicalTapeLogicalTapeImport (LogicalTapeSet *lts, int worker, TapeShare *shared)
 
void LogicalTapeSetForgetFreeSpace (LogicalTapeSet *lts)
 
size_t LogicalTapeRead (LogicalTape *lt, void *ptr, size_t size)
 
void LogicalTapeWrite (LogicalTape *lt, void *ptr, size_t size)
 
void LogicalTapeRewindForRead (LogicalTape *lt, size_t buffer_size)
 
void LogicalTapeFreeze (LogicalTape *lt, TapeShare *share)
 
size_t LogicalTapeBackspace (LogicalTape *lt, size_t size)
 
void LogicalTapeSeek (LogicalTape *lt, long blocknum, int offset)
 
void LogicalTapeTell (LogicalTape *lt, long *blocknum, int *offset)
 
long LogicalTapeSetBlocks (LogicalTapeSet *lts)
 

Typedef Documentation

◆ LogicalTape

typedef struct LogicalTape LogicalTape

Definition at line 1 of file logtape.h.

◆ LogicalTapeSet

Definition at line 1 of file logtape.h.

◆ TapeShare

typedef struct TapeShare TapeShare

Function Documentation

◆ LogicalTapeBackspace()

size_t LogicalTapeBackspace ( LogicalTape lt,
size_t  size 
)

Definition at line 1071 of file logtape.c.

1072 {
1073  size_t seekpos = 0;
1074 
1075  Assert(lt->frozen);
1076  Assert(lt->buffer_size == BLCKSZ);
1077 
1078  if (lt->buffer == NULL)
1079  ltsInitReadBuffer(lt);
1080 
1081  /*
1082  * Easy case for seek within current block.
1083  */
1084  if (size <= (size_t) lt->pos)
1085  {
1086  lt->pos -= (int) size;
1087  return size;
1088  }
1089 
1090  /*
1091  * Not-so-easy case, have to walk back the chain of blocks. This
1092  * implementation would be pretty inefficient for long seeks, but we
1093  * really aren't doing that (a seek over one tuple is typical).
1094  */
1095  seekpos = (size_t) lt->pos; /* part within this block */
1096  while (size > seekpos)
1097  {
1098  long prev = TapeBlockGetTrailer(lt->buffer)->prev;
1099 
1100  if (prev == -1L)
1101  {
1102  /* Tried to back up beyond the beginning of tape. */
1103  if (lt->curBlockNumber != lt->firstBlockNumber)
1104  elog(ERROR, "unexpected end of tape");
1105  lt->pos = 0;
1106  return seekpos;
1107  }
1108 
1109  ltsReadBlock(lt->tapeSet, prev, (void *) lt->buffer);
1110 
1111  if (TapeBlockGetTrailer(lt->buffer)->next != lt->curBlockNumber)
1112  elog(ERROR, "broken tape, next of block %ld is %ld, expected %ld",
1113  prev,
1114  TapeBlockGetTrailer(lt->buffer)->next,
1115  lt->curBlockNumber);
1116 
1118  lt->curBlockNumber = prev;
1119  lt->nextBlockNumber = TapeBlockGetTrailer(lt->buffer)->next;
1120 
1121  seekpos += TapeBlockPayloadSize;
1122  }
1123 
1124  /*
1125  * 'seekpos' can now be greater than 'size', because it points to the
1126  * beginning the target block. The difference is the position within the
1127  * page.
1128  */
1129  lt->pos = seekpos - size;
1130  return size;
1131 }
#define ERROR
Definition: elog.h:33
#define elog(elevel,...)
Definition: elog.h:218
Assert(fmt[strlen(fmt) - 1] !='\n')
#define TapeBlockGetTrailer(buf)
Definition: logtape.c:104
#define TapeBlockPayloadSize
Definition: logtape.c:103
static void ltsInitReadBuffer(LogicalTape *lt)
Definition: logtape.c:537
static void ltsReadBlock(LogicalTapeSet *lts, long blocknum, void *buffer)
Definition: logtape.c:282
while(p+4<=pend)
long curBlockNumber
Definition: logtape.c:157
char * buffer
Definition: logtape.c:164
bool frozen
Definition: logtape.c:142
long nextBlockNumber
Definition: logtape.c:158
int buffer_size
Definition: logtape.c:165
long firstBlockNumber
Definition: logtape.c:156
LogicalTapeSet * tapeSet
Definition: logtape.c:139
int nbytes
Definition: logtape.c:168

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

Referenced by tuplesort_gettuple_common().

◆ LogicalTapeClose()

void LogicalTapeClose ( LogicalTape lt)

Definition at line 742 of file logtape.c.

743 {
744  if (lt->buffer)
745  pfree(lt->buffer);
746  pfree(lt);
747 }
void pfree(void *pointer)
Definition: mcxt.c:1169

References LogicalTape::buffer, and pfree().

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

◆ LogicalTapeCreate()

LogicalTape* LogicalTapeCreate ( LogicalTapeSet lts)

Definition at line 689 of file logtape.c.

690 {
691  /*
692  * The only thing that currently prevents creating new tapes in leader is
693  * the fact that BufFiles opened using BufFileOpenShared() are read-only
694  * by definition, but that could be changed if it seemed worthwhile. For
695  * now, writing to the leader tape will raise a "Bad file descriptor"
696  * error, so tuplesort must avoid writing to the leader tape altogether.
697  */
698  if (lts->fileset && lts->worker == -1)
699  elog(ERROR, "cannot create new tapes in leader process");
700 
701  return ltsCreateTape(lts);
702 }
static LogicalTape * ltsCreateTape(LogicalTapeSet *lts)
Definition: logtape.c:705
SharedFileSet * fileset
Definition: logtape.c:190

References elog, ERROR, LogicalTapeSet::fileset, ltsCreateTape(), and LogicalTapeSet::worker.

Referenced by hashagg_spill_init(), and selectnewtape().

◆ LogicalTapeFreeze()

void LogicalTapeFreeze ( LogicalTape lt,
TapeShare share 
)

Definition at line 990 of file logtape.c.

991 {
992  LogicalTapeSet *lts = lt->tapeSet;
993 
994  Assert(lt->writing);
995  Assert(lt->offsetBlockNumber == 0L);
996 
997  /*
998  * Completion of a write phase. Flush last partial data block, and rewind
999  * for nondestructive read.
1000  */
1001  if (lt->dirty)
1002  {
1003  /*
1004  * As long as we've filled the buffer at least once, its contents are
1005  * entirely defined from valgrind's point of view, even though
1006  * contents beyond the current end point may be stale. But it's
1007  * possible - at least in the case of a parallel sort - to sort such
1008  * small amount of data that we do not fill the buffer even once. Tell
1009  * valgrind that its contents are defined, so it doesn't bleat.
1010  */
1012  lt->buffer_size - lt->nbytes);
1013 
1014  TapeBlockSetNBytes(lt->buffer, lt->nbytes);
1015  ltsWriteBlock(lt->tapeSet, lt->curBlockNumber, (void *) lt->buffer);
1016  }
1017  lt->writing = false;
1018  lt->frozen = true;
1019 
1020  /*
1021  * The seek and backspace functions assume a single block read buffer.
1022  * That's OK with current usage. A larger buffer is helpful to make the
1023  * read pattern of the backing file look more sequential to the OS, when
1024  * we're reading from multiple tapes. But at the end of a sort, when a
1025  * tape is frozen, we only read from a single tape anyway.
1026  */
1027  if (!lt->buffer || lt->buffer_size != BLCKSZ)
1028  {
1029  if (lt->buffer)
1030  pfree(lt->buffer);
1031  lt->buffer = palloc(BLCKSZ);
1032  lt->buffer_size = BLCKSZ;
1033  }
1034 
1035  /* Read the first block, or reset if tape is empty */
1036  lt->curBlockNumber = lt->firstBlockNumber;
1037  lt->pos = 0;
1038  lt->nbytes = 0;
1039 
1040  if (lt->firstBlockNumber == -1L)
1041  lt->nextBlockNumber = -1L;
1042  ltsReadBlock(lt->tapeSet, lt->curBlockNumber, (void *) lt->buffer);
1043  if (TapeBlockIsLast(lt->buffer))
1044  lt->nextBlockNumber = -1L;
1045  else
1046  lt->nextBlockNumber = TapeBlockGetTrailer(lt->buffer)->next;
1047  lt->nbytes = TapeBlockGetNBytes(lt->buffer);
1048 
1049  /* Handle extra steps when caller is to share its tapeset */
1050  if (share)
1051  {
1053  share->firstblocknumber = lt->firstBlockNumber;
1054  }
1055 }
void BufFileExportFileSet(BufFile *file)
Definition: buffile.c:389
#define TapeBlockIsLast(buf)
Definition: logtape.c:107
#define TapeBlockGetNBytes(buf)
Definition: logtape.c:108
static void ltsWriteBlock(LogicalTapeSet *lts, long blocknum, void *buffer)
Definition: logtape.c:238
#define TapeBlockSetNBytes(buf, nbytes)
Definition: logtape.c:111
void * palloc(Size size)
Definition: mcxt.c:1062
#define VALGRIND_MAKE_MEM_DEFINED(addr, size)
Definition: memdebug.h:26
BufFile * pfile
Definition: logtape.c:189
long offsetBlockNumber
Definition: logtape.c:159
bool writing
Definition: logtape.c:141
bool dirty
Definition: logtape.c:143
long firstblocknumber
Definition: logtape.h:54

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

Referenced by mergeruns(), and worker_freeze_result_tape().

◆ LogicalTapeImport()

LogicalTape* LogicalTapeImport ( LogicalTapeSet lts,
int  worker,
TapeShare shared 
)

Definition at line 618 of file logtape.c.

619 {
620  LogicalTape *lt;
621  long tapeblocks;
622  char filename[MAXPGPATH];
623  BufFile *file;
624  int64 filesize;
625 
626  lt = ltsCreateTape(lts);
627 
628  /*
629  * build concatenated view of all buffiles, remembering the block number
630  * where each source file begins.
631  */
632  pg_itoa(worker, filename);
633  file = BufFileOpenFileSet(&lts->fileset->fs, filename, O_RDONLY, false);
634  filesize = BufFileSize(file);
635 
636  /*
637  * Stash first BufFile, and concatenate subsequent BufFiles to that. Store
638  * block offset into each tape as we go.
639  */
640  lt->firstBlockNumber = shared->firstblocknumber;
641  if (lts->pfile == NULL)
642  {
643  lts->pfile = file;
644  lt->offsetBlockNumber = 0L;
645  }
646  else
647  {
648  lt->offsetBlockNumber = BufFileAppend(lts->pfile, file);
649  }
650  /* Don't allocate more for read buffer than could possibly help */
651  lt->max_size = Min(MaxAllocSize, filesize);
652  tapeblocks = filesize / BLCKSZ;
653 
654  /*
655  * Update # of allocated blocks and # blocks written to reflect the
656  * imported BufFile. Allocated/written blocks include space used by holes
657  * left between concatenated BufFiles. Also track the number of hole
658  * blocks so that we can later work backwards to calculate the number of
659  * physical blocks for instrumentation.
660  */
662 
663  lts->nBlocksAllocated = lt->offsetBlockNumber + tapeblocks;
664  lts->nBlocksWritten = lts->nBlocksAllocated;
665 
666  return lt;
667 }
long BufFileAppend(BufFile *target, BufFile *source)
Definition: buffile.c:845
BufFile * BufFileOpenFileSet(FileSet *fileset, const char *name, int mode, bool missing_ok)
Definition: buffile.c:286
int64 BufFileSize(BufFile *file)
Definition: buffile.c:806
#define Min(x, y)
Definition: c.h:986
#define MaxAllocSize
Definition: memutils.h:40
int pg_itoa(int16 i, char *a)
Definition: numutils.c:338
#define MAXPGPATH
static char * filename
Definition: pg_dumpall.c:92
long nBlocksAllocated
Definition: logtape.c:203
long nHoleBlocks
Definition: logtape.c:205
long nBlocksWritten
Definition: logtape.c:204
int max_size
Definition: logtape.c:166

References BufFileAppend(), BufFileOpenFileSet(), BufFileSize(), filename, LogicalTapeSet::fileset, LogicalTape::firstBlockNumber, TapeShare::firstblocknumber, SharedFileSet::fs, ltsCreateTape(), LogicalTape::max_size, MaxAllocSize, MAXPGPATH, Min, LogicalTapeSet::nBlocksAllocated, LogicalTapeSet::nBlocksWritten, LogicalTapeSet::nHoleBlocks, LogicalTape::offsetBlockNumber, LogicalTapeSet::pfile, and pg_itoa().

Referenced by leader_takeover_tapes().

◆ LogicalTapeRead()

size_t LogicalTapeRead ( LogicalTape lt,
void *  ptr,
size_t  size 
)

Definition at line 937 of file logtape.c.

938 {
939  size_t nread = 0;
940  size_t nthistime;
941 
942  Assert(!lt->writing);
943 
944  if (lt->buffer == NULL)
945  ltsInitReadBuffer(lt);
946 
947  while (size > 0)
948  {
949  if (lt->pos >= lt->nbytes)
950  {
951  /* Try to load more data into buffer. */
952  if (!ltsReadFillBuffer(lt))
953  break; /* EOF */
954  }
955 
956  nthistime = lt->nbytes - lt->pos;
957  if (nthistime > size)
958  nthistime = size;
959  Assert(nthistime > 0);
960 
961  memcpy(ptr, lt->buffer + lt->pos, nthistime);
962 
963  lt->pos += nthistime;
964  ptr = (void *) ((char *) ptr + nthistime);
965  size -= nthistime;
966  nread += nthistime;
967  }
968 
969  return nread;
970 }
static bool ltsReadFillBuffer(LogicalTape *lt)
Definition: logtape.c:305

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

Referenced by getlen(), and hashagg_batch_read().

◆ LogicalTapeRewindForRead()

void LogicalTapeRewindForRead ( LogicalTape lt,
size_t  buffer_size 
)

Definition at line 855 of file logtape.c.

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

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, LogicalTape::tapeSet, VALGRIND_MAKE_MEM_DEFINED, and LogicalTape::writing.

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

◆ LogicalTapeSeek()

void LogicalTapeSeek ( LogicalTape lt,
long  blocknum,
int  offset 
)

Definition at line 1142 of file logtape.c.

1143 {
1144  Assert(lt->frozen);
1145  Assert(offset >= 0 && offset <= TapeBlockPayloadSize);
1146  Assert(lt->buffer_size == BLCKSZ);
1147 
1148  if (lt->buffer == NULL)
1149  ltsInitReadBuffer(lt);
1150 
1151  if (blocknum != lt->curBlockNumber)
1152  {
1153  ltsReadBlock(lt->tapeSet, blocknum, (void *) lt->buffer);
1154  lt->curBlockNumber = blocknum;
1156  lt->nextBlockNumber = TapeBlockGetTrailer(lt->buffer)->next;
1157  }
1158 
1159  if (offset > lt->nbytes)
1160  elog(ERROR, "invalid tape seek position");
1161  lt->pos = offset;
1162 }

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

Referenced by tuplesort_restorepos().

◆ LogicalTapeSetBlocks()

long LogicalTapeSetBlocks ( LogicalTapeSet lts)

Definition at line 1192 of file logtape.c.

1193 {
1194  return lts->nBlocksWritten - lts->nHoleBlocks;
1195 }

References LogicalTapeSet::nBlocksWritten, and LogicalTapeSet::nHoleBlocks.

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

◆ LogicalTapeSetClose()

void LogicalTapeSetClose ( LogicalTapeSet lts)

Definition at line 676 of file logtape.c.

677 {
678  BufFileClose(lts->pfile);
679  pfree(lts->freeBlocks);
680  pfree(lts);
681 }
void BufFileClose(BufFile *file)
Definition: buffile.c:407
long * freeBlocks
Definition: logtape.c:216

References BufFileClose(), LogicalTapeSet::freeBlocks, LogicalTapeSet::pfile, and pfree().

Referenced by hashagg_reset_spill_state(), and tuplesort_free().

◆ LogicalTapeSetCreate()

LogicalTapeSet* LogicalTapeSetCreate ( bool  preallocate,
SharedFileSet fileset,
int  worker 
)

Definition at line 565 of file logtape.c.

566 {
567  LogicalTapeSet *lts;
568 
569  /*
570  * Create top-level struct including per-tape LogicalTape structs.
571  */
572  lts = (LogicalTapeSet *) palloc(sizeof(LogicalTapeSet));
573  lts->nBlocksAllocated = 0L;
574  lts->nBlocksWritten = 0L;
575  lts->nHoleBlocks = 0L;
576  lts->forgetFreeSpace = false;
577  lts->freeBlocksLen = 32; /* reasonable initial guess */
578  lts->freeBlocks = (long *) palloc(lts->freeBlocksLen * sizeof(long));
579  lts->nFreeBlocks = 0;
580  lts->enable_prealloc = preallocate;
581 
582  lts->fileset = fileset;
583  lts->worker = worker;
584 
585  /*
586  * Create temp BufFile storage as required.
587  *
588  * In leader, we hijack the BufFile of the first tape that's imported, and
589  * concatenate the BufFiles of any subsequent tapes to that. Hence don't
590  * create a BufFile here. Things are simpler for the worker case and the
591  * serial case, though. They are generally very similar -- workers use a
592  * shared fileset, whereas serial sorts use a conventional serial BufFile.
593  */
594  if (fileset && worker == -1)
595  lts->pfile = NULL;
596  else if (fileset)
597  {
598  char filename[MAXPGPATH];
599 
600  pg_itoa(worker, filename);
601  lts->pfile = BufFileCreateFileSet(&fileset->fs, filename);
602  }
603  else
604  lts->pfile = BufFileCreateTemp(false);
605 
606  return lts;
607 }
BufFile * BufFileCreateTemp(bool interXact)
Definition: buffile.c:188
BufFile * BufFileCreateFileSet(FileSet *fileset, const char *name)
Definition: buffile.c:262
long nFreeBlocks
Definition: logtape.c:217
bool forgetFreeSpace
Definition: logtape.c:215
Size freeBlocksLen
Definition: logtape.c:218
bool enable_prealloc
Definition: logtape.c:219

References BufFileCreateFileSet(), BufFileCreateTemp(), LogicalTapeSet::enable_prealloc, filename, LogicalTapeSet::fileset, LogicalTapeSet::forgetFreeSpace, LogicalTapeSet::freeBlocks, LogicalTapeSet::freeBlocksLen, SharedFileSet::fs, MAXPGPATH, LogicalTapeSet::nBlocksAllocated, LogicalTapeSet::nBlocksWritten, LogicalTapeSet::nFreeBlocks, LogicalTapeSet::nHoleBlocks, palloc(), LogicalTapeSet::pfile, pg_itoa(), and LogicalTapeSet::worker.

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

◆ LogicalTapeSetForgetFreeSpace()

void LogicalTapeSetForgetFreeSpace ( LogicalTapeSet lts)

Definition at line 759 of file logtape.c.

760 {
761  lts->forgetFreeSpace = true;
762 }

References LogicalTapeSet::forgetFreeSpace.

Referenced by mergeruns().

◆ LogicalTapeTell()

void LogicalTapeTell ( LogicalTape lt,
long *  blocknum,
int *  offset 
)

Definition at line 1171 of file logtape.c.

1172 {
1173  if (lt->buffer == NULL)
1174  ltsInitReadBuffer(lt);
1175 
1176  Assert(lt->offsetBlockNumber == 0L);
1177 
1178  /* With a larger buffer, 'pos' wouldn't be the same as offset within page */
1179  Assert(lt->buffer_size == BLCKSZ);
1180 
1181  *blocknum = lt->curBlockNumber;
1182  *offset = lt->pos;
1183 }

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

Referenced by tuplesort_markpos().

◆ LogicalTapeWrite()

void LogicalTapeWrite ( LogicalTape lt,
void *  ptr,
size_t  size 
)

Definition at line 770 of file logtape.c.

771 {
772  LogicalTapeSet *lts = lt->tapeSet;
773  size_t nthistime;
774 
775  Assert(lt->writing);
776  Assert(lt->offsetBlockNumber == 0L);
777 
778  /* Allocate data buffer and first block on first write */
779  if (lt->buffer == NULL)
780  {
781  lt->buffer = (char *) palloc(BLCKSZ);
782  lt->buffer_size = BLCKSZ;
783  }
784  if (lt->curBlockNumber == -1)
785  {
786  Assert(lt->firstBlockNumber == -1);
787  Assert(lt->pos == 0);
788 
789  lt->curBlockNumber = ltsGetBlock(lts, lt);
791 
792  TapeBlockGetTrailer(lt->buffer)->prev = -1L;
793  }
794 
795  Assert(lt->buffer_size == BLCKSZ);
796  while (size > 0)
797  {
798  if (lt->pos >= (int) TapeBlockPayloadSize)
799  {
800  /* Buffer full, dump it out */
801  long nextBlockNumber;
802 
803  if (!lt->dirty)
804  {
805  /* Hmm, went directly from reading to writing? */
806  elog(ERROR, "invalid logtape state: should be dirty");
807  }
808 
809  /*
810  * First allocate the next block, so that we can store it in the
811  * 'next' pointer of this block.
812  */
813  nextBlockNumber = ltsGetBlock(lt->tapeSet, lt);
814 
815  /* set the next-pointer and dump the current block. */
816  TapeBlockGetTrailer(lt->buffer)->next = nextBlockNumber;
817  ltsWriteBlock(lt->tapeSet, lt->curBlockNumber, (void *) lt->buffer);
818 
819  /* initialize the prev-pointer of the next block */
820  TapeBlockGetTrailer(lt->buffer)->prev = lt->curBlockNumber;
821  lt->curBlockNumber = nextBlockNumber;
822  lt->pos = 0;
823  lt->nbytes = 0;
824  }
825 
826  nthistime = TapeBlockPayloadSize - lt->pos;
827  if (nthistime > size)
828  nthistime = size;
829  Assert(nthistime > 0);
830 
831  memcpy(lt->buffer + lt->pos, ptr, nthistime);
832 
833  lt->dirty = true;
834  lt->pos += nthistime;
835  if (lt->nbytes < lt->pos)
836  lt->nbytes = lt->pos;
837  ptr = (void *) ((char *) ptr + nthistime);
838  size -= nthistime;
839  }
840 }
static long ltsGetBlock(LogicalTapeSet *lts, LogicalTape *lt)
Definition: logtape.c:375

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

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