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

Go to the source code of this file.

Data Structures

struct  TapeBlockTrailer
 
struct  LogicalTape
 
struct  LogicalTapeSet
 

Macros

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

Typedefs

typedef struct TapeBlockTrailer TapeBlockTrailer
 
typedef struct LogicalTape LogicalTape
 

Functions

static void ltsWriteBlock (LogicalTapeSet *lts, long blocknum, void *buffer)
 
static void ltsReadBlock (LogicalTapeSet *lts, long blocknum, void *buffer)
 
static long ltsGetFreeBlock (LogicalTapeSet *lts)
 
static void ltsReleaseBlock (LogicalTapeSet *lts, long blocknum)
 
static bool ltsReadFillBuffer (LogicalTapeSet *lts, LogicalTape *lt)
 
static int freeBlocks_cmp (const void *a, const void *b)
 
LogicalTapeSetLogicalTapeSetCreate (int ntapes)
 
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)
 
size_t LogicalTapeBackspace (LogicalTapeSet *lts, int tapenum, size_t size)
 
void LogicalTapeSeek (LogicalTapeSet *lts, int tapenum, long blocknum, int offset)
 
void LogicalTapeTell (LogicalTapeSet *lts, int tapenum, long *blocknum, int *offset)
 
long LogicalTapeSetBlocks (LogicalTapeSet *lts)
 

Macro Definition Documentation

◆ TapeBlockGetNBytes

#define TapeBlockGetNBytes (   buf)
Value:
#define TapeBlockIsLast(buf)
Definition: logtape.c:101
#define TapeBlockPayloadSize
Definition: logtape.c:97
static char * buf
Definition: pg_test_fsync.c:67
#define TapeBlockGetTrailer(buf)
Definition: logtape.c:98

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

Referenced by LogicalTapeFreeze(), and ltsReadFillBuffer().

◆ TapeBlockPayloadSize

#define TapeBlockPayloadSize   (BLCKSZ - sizeof(TapeBlockTrailer))

Definition at line 97 of file logtape.c.

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

◆ TapeBlockSetNBytes

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

Definition at line 105 of file logtape.c.

Referenced by LogicalTapeFreeze(), and LogicalTapeRewindForRead().

Typedef Documentation

◆ LogicalTape

◆ TapeBlockTrailer

Function Documentation

◆ freeBlocks_cmp()

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

Definition at line 301 of file logtape.c.

Referenced by ltsGetFreeBlock().

302 {
303  long ablk = *((const long *) a);
304  long bblk = *((const long *) b);
305 
306  /* can't just subtract because long might be wider than int */
307  if (ablk < bblk)
308  return 1;
309  if (ablk > bblk)
310  return -1;
311  return 0;
312 }

◆ LogicalTapeBackspace()

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

Definition at line 768 of file logtape.c.

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

Referenced by tuplesort_gettuple_common().

769 {
770  LogicalTape *lt;
771  size_t seekpos = 0;
772 
773  Assert(tapenum >= 0 && tapenum < lts->nTapes);
774  lt = &lts->tapes[tapenum];
775  Assert(lt->frozen);
776  Assert(lt->buffer_size == BLCKSZ);
777 
778  /*
779  * Easy case for seek within current block.
780  */
781  if (size <= (size_t) lt->pos)
782  {
783  lt->pos -= (int) size;
784  return size;
785  }
786 
787  /*
788  * Not-so-easy case, have to walk back the chain of blocks. This
789  * implementation would be pretty inefficient for long seeks, but we
790  * really aren't doing that (a seek over one tuple is typical).
791  */
792  seekpos = (size_t) lt->pos; /* part within this block */
793  while (size > seekpos)
794  {
795  long prev = TapeBlockGetTrailer(lt->buffer)->prev;
796 
797  if (prev == -1L)
798  {
799  /* Tried to back up beyond the beginning of tape. */
800  if (lt->curBlockNumber != lt->firstBlockNumber)
801  elog(ERROR, "unexpected end of tape");
802  lt->pos = 0;
803  return seekpos;
804  }
805 
806  ltsReadBlock(lts, prev, (void *) lt->buffer);
807 
808  if (TapeBlockGetTrailer(lt->buffer)->next != lt->curBlockNumber)
809  elog(ERROR, "broken tape, next of block %ld is %ld, expected %ld",
810  prev,
811  TapeBlockGetTrailer(lt->buffer)->next,
812  lt->curBlockNumber);
813 
815  lt->curBlockNumber = prev;
816  lt->nextBlockNumber = TapeBlockGetTrailer(lt->buffer)->next;
817 
818  seekpos += TapeBlockPayloadSize;
819  }
820 
821  /*
822  * 'seekpos' can now be greater than 'size', because it points to the
823  * beginning the target block. The difference is the position within the
824  * page.
825  */
826  lt->pos = seekpos - size;
827  return size;
828 }
LogicalTape tapes[FLEXIBLE_ARRAY_MEMBER]
Definition: logtape.c:188
#define TapeBlockPayloadSize
Definition: logtape.c:97
bool frozen
Definition: logtape.c:122
long nextBlockNumber
Definition: logtape.c:135
#define ERROR
Definition: elog.h:43
int nbytes
Definition: logtape.c:143
long firstBlockNumber
Definition: logtape.c:133
long curBlockNumber
Definition: logtape.c:134
#define Assert(condition)
Definition: c.h:680
char * buffer
Definition: logtape.c:140
#define elog
Definition: elog.h:219
int buffer_size
Definition: logtape.c:141
#define TapeBlockGetTrailer(buf)
Definition: logtape.c:98
static void ltsReadBlock(LogicalTapeSet *lts, long blocknum, void *buffer)
Definition: logtape.c:246

◆ LogicalTapeFreeze()

void LogicalTapeFreeze ( LogicalTapeSet lts,
int  tapenum 
)

Definition at line 703 of file logtape.c.

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

Referenced by mergeruns().

704 {
705  LogicalTape *lt;
706 
707  Assert(tapenum >= 0 && tapenum < lts->nTapes);
708  lt = &lts->tapes[tapenum];
709  Assert(lt->writing);
710 
711  /*
712  * Completion of a write phase. Flush last partial data block, and rewind
713  * for nondestructive read.
714  */
715  if (lt->dirty)
716  {
717  TapeBlockSetNBytes(lt->buffer, lt->nbytes);
718  ltsWriteBlock(lts, lt->curBlockNumber, (void *) lt->buffer);
719  lt->writing = false;
720  }
721  lt->writing = false;
722  lt->frozen = true;
723 
724  /*
725  * The seek and backspace functions assume a single block read buffer.
726  * That's OK with current usage. A larger buffer is helpful to make the
727  * read pattern of the backing file look more sequential to the OS, when
728  * we're reading from multiple tapes. But at the end of a sort, when a
729  * tape is frozen, we only read from a single tape anyway.
730  */
731  if (!lt->buffer || lt->buffer_size != BLCKSZ)
732  {
733  if (lt->buffer)
734  pfree(lt->buffer);
735  lt->buffer = palloc(BLCKSZ);
736  lt->buffer_size = BLCKSZ;
737  }
738 
739  /* Read the first block, or reset if tape is empty */
741  lt->pos = 0;
742  lt->nbytes = 0;
743 
744  if (lt->firstBlockNumber == -1L)
745  lt->nextBlockNumber = -1L;
746  ltsReadBlock(lts, lt->curBlockNumber, (void *) lt->buffer);
747  if (TapeBlockIsLast(lt->buffer))
748  lt->nextBlockNumber = -1L;
749  else
750  lt->nextBlockNumber = TapeBlockGetTrailer(lt->buffer)->next;
751  lt->nbytes = TapeBlockGetNBytes(lt->buffer);
752 }
LogicalTape tapes[FLEXIBLE_ARRAY_MEMBER]
Definition: logtape.c:188
#define TapeBlockIsLast(buf)
Definition: logtape.c:101
bool frozen
Definition: logtape.c:122
long nextBlockNumber
Definition: logtape.c:135
bool writing
Definition: logtape.c:121
bool dirty
Definition: logtape.c:123
void pfree(void *pointer)
Definition: mcxt.c:936
int nbytes
Definition: logtape.c:143
long firstBlockNumber
Definition: logtape.c:133
#define TapeBlockSetNBytes(buf, nbytes)
Definition: logtape.c:105
long curBlockNumber
Definition: logtape.c:134
#define Assert(condition)
Definition: c.h:680
#define TapeBlockGetNBytes(buf)
Definition: logtape.c:102
char * buffer
Definition: logtape.c:140
void * palloc(Size size)
Definition: mcxt.c:835
int buffer_size
Definition: logtape.c:141
static void ltsWriteBlock(LogicalTapeSet *lts, long blocknum, void *buffer)
Definition: logtape.c:203
#define TapeBlockGetTrailer(buf)
Definition: logtape.c:98
static void ltsReadBlock(LogicalTapeSet *lts, long blocknum, void *buffer)
Definition: logtape.c:246

◆ LogicalTapeRead()

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

Definition at line 655 of file logtape.c.

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

Referenced by getlen().

657 {
658  LogicalTape *lt;
659  size_t nread = 0;
660  size_t nthistime;
661 
662  Assert(tapenum >= 0 && tapenum < lts->nTapes);
663  lt = &lts->tapes[tapenum];
664  Assert(!lt->writing);
665 
666  while (size > 0)
667  {
668  if (lt->pos >= lt->nbytes)
669  {
670  /* Try to load more data into buffer. */
671  if (!ltsReadFillBuffer(lts, lt))
672  break; /* EOF */
673  }
674 
675  nthistime = lt->nbytes - lt->pos;
676  if (nthistime > size)
677  nthistime = size;
678  Assert(nthistime > 0);
679 
680  memcpy(ptr, lt->buffer + lt->pos, nthistime);
681 
682  lt->pos += nthistime;
683  ptr = (void *) ((char *) ptr + nthistime);
684  size -= nthistime;
685  nread += nthistime;
686  }
687 
688  return nread;
689 }
LogicalTape tapes[FLEXIBLE_ARRAY_MEMBER]
Definition: logtape.c:188
static bool ltsReadFillBuffer(LogicalTapeSet *lts, LogicalTape *lt)
Definition: logtape.c:262
bool writing
Definition: logtape.c:121
int nbytes
Definition: logtape.c:143
#define Assert(condition)
Definition: c.h:680
char * buffer
Definition: logtape.c:140

◆ LogicalTapeRewindForRead()

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

Definition at line 551 of file logtape.c.

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

Referenced by mergeruns(), and tuplesort_rescan().

552 {
553  LogicalTape *lt;
554 
555  Assert(tapenum >= 0 && tapenum < lts->nTapes);
556  lt = &lts->tapes[tapenum];
557 
558  /*
559  * Round and cap buffer_size if needed.
560  */
561  if (lt->frozen)
562  buffer_size = BLCKSZ;
563  else
564  {
565  /* need at least one block */
566  if (buffer_size < BLCKSZ)
567  buffer_size = BLCKSZ;
568 
569  /*
570  * palloc() larger than MaxAllocSize would fail (a multi-gigabyte
571  * buffer is unlikely to be helpful, anyway)
572  */
573  if (buffer_size > MaxAllocSize)
574  buffer_size = MaxAllocSize;
575 
576  /* round down to BLCKSZ boundary */
577  buffer_size -= buffer_size % BLCKSZ;
578  }
579 
580  if (lt->writing)
581  {
582  /*
583  * Completion of a write phase. Flush last partial data block, and
584  * rewind for normal (destructive) read.
585  */
586  if (lt->dirty)
587  {
588  TapeBlockSetNBytes(lt->buffer, lt->nbytes);
589  ltsWriteBlock(lts, lt->curBlockNumber, (void *) lt->buffer);
590  }
591  lt->writing = false;
592  }
593  else
594  {
595  /*
596  * This is only OK if tape is frozen; we rewind for (another) read
597  * pass.
598  */
599  Assert(lt->frozen);
600  }
601 
602  /* Allocate a read buffer (unless the tape is empty) */
603  if (lt->buffer)
604  pfree(lt->buffer);
605  lt->buffer = NULL;
606  lt->buffer_size = 0;
607  if (lt->firstBlockNumber != -1L)
608  {
609  lt->buffer = palloc(buffer_size);
610  lt->buffer_size = buffer_size;
611  }
612 
613  /* Read the first block, or reset if tape is empty */
615  lt->pos = 0;
616  lt->nbytes = 0;
617  ltsReadFillBuffer(lts, lt);
618 }
LogicalTape tapes[FLEXIBLE_ARRAY_MEMBER]
Definition: logtape.c:188
static bool ltsReadFillBuffer(LogicalTapeSet *lts, LogicalTape *lt)
Definition: logtape.c:262
bool frozen
Definition: logtape.c:122
long nextBlockNumber
Definition: logtape.c:135
bool writing
Definition: logtape.c:121
bool dirty
Definition: logtape.c:123
void pfree(void *pointer)
Definition: mcxt.c:936
int nbytes
Definition: logtape.c:143
#define MaxAllocSize
Definition: memutils.h:40
long firstBlockNumber
Definition: logtape.c:133
#define TapeBlockSetNBytes(buf, nbytes)
Definition: logtape.c:105
long curBlockNumber
Definition: logtape.c:134
#define Assert(condition)
Definition: c.h:680
char * buffer
Definition: logtape.c:140
void * palloc(Size size)
Definition: mcxt.c:835
int buffer_size
Definition: logtape.c:141
static void ltsWriteBlock(LogicalTapeSet *lts, long blocknum, void *buffer)
Definition: logtape.c:203

◆ LogicalTapeRewindForWrite()

void LogicalTapeRewindForWrite ( LogicalTapeSet lts,
int  tapenum 
)

Definition at line 629 of file logtape.c.

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

Referenced by mergeruns(), and tuplesort_gettuple_common().

630 {
631  LogicalTape *lt;
632 
633  Assert(tapenum >= 0 && tapenum < lts->nTapes);
634  lt = &lts->tapes[tapenum];
635 
636  Assert(!lt->writing && !lt->frozen);
637  lt->writing = true;
638  lt->dirty = false;
639  lt->firstBlockNumber = -1L;
640  lt->curBlockNumber = -1L;
641  lt->pos = 0;
642  lt->nbytes = 0;
643  if (lt->buffer)
644  pfree(lt->buffer);
645  lt->buffer = NULL;
646  lt->buffer_size = 0;
647 }
LogicalTape tapes[FLEXIBLE_ARRAY_MEMBER]
Definition: logtape.c:188
bool frozen
Definition: logtape.c:122
bool writing
Definition: logtape.c:121
bool dirty
Definition: logtape.c:123
void pfree(void *pointer)
Definition: mcxt.c:936
int nbytes
Definition: logtape.c:143
long firstBlockNumber
Definition: logtape.c:133
long curBlockNumber
Definition: logtape.c:134
#define Assert(condition)
Definition: c.h:680
char * buffer
Definition: logtape.c:140
int buffer_size
Definition: logtape.c:141

◆ LogicalTapeSeek()

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

Definition at line 839 of file logtape.c.

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

Referenced by tuplesort_restorepos().

841 {
842  LogicalTape *lt;
843 
844  Assert(tapenum >= 0 && tapenum < lts->nTapes);
845  lt = &lts->tapes[tapenum];
846  Assert(lt->frozen);
847  Assert(offset >= 0 && offset <= TapeBlockPayloadSize);
848  Assert(lt->buffer_size == BLCKSZ);
849 
850  if (blocknum != lt->curBlockNumber)
851  {
852  ltsReadBlock(lts, blocknum, (void *) lt->buffer);
853  lt->curBlockNumber = blocknum;
855  lt->nextBlockNumber = TapeBlockGetTrailer(lt->buffer)->next;
856  }
857 
858  if (offset > lt->nbytes)
859  elog(ERROR, "invalid tape seek position");
860  lt->pos = offset;
861 }
LogicalTape tapes[FLEXIBLE_ARRAY_MEMBER]
Definition: logtape.c:188
#define TapeBlockPayloadSize
Definition: logtape.c:97
bool frozen
Definition: logtape.c:122
long nextBlockNumber
Definition: logtape.c:135
#define ERROR
Definition: elog.h:43
int nbytes
Definition: logtape.c:143
long curBlockNumber
Definition: logtape.c:134
#define Assert(condition)
Definition: c.h:680
char * buffer
Definition: logtape.c:140
#define elog
Definition: elog.h:219
int buffer_size
Definition: logtape.c:141
#define TapeBlockGetTrailer(buf)
Definition: logtape.c:98
static void ltsReadBlock(LogicalTapeSet *lts, long blocknum, void *buffer)
Definition: logtape.c:246

◆ LogicalTapeSetBlocks()

long LogicalTapeSetBlocks ( LogicalTapeSet lts)

Definition at line 889 of file logtape.c.

References LogicalTapeSet::nBlocksAllocated.

Referenced by tuplesort_end(), and tuplesort_get_stats().

890 {
891  return lts->nBlocksAllocated;
892 }
long nBlocksAllocated
Definition: logtape.c:164

◆ LogicalTapeSetClose()

void LogicalTapeSetClose ( LogicalTapeSet lts)

Definition at line 427 of file logtape.c.

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

Referenced by tuplesort_end().

428 {
429  LogicalTape *lt;
430  int i;
431 
432  BufFileClose(lts->pfile);
433  for (i = 0; i < lts->nTapes; i++)
434  {
435  lt = &lts->tapes[i];
436  if (lt->buffer)
437  pfree(lt->buffer);
438  }
439  pfree(lts->freeBlocks);
440  pfree(lts);
441 }
LogicalTape tapes[FLEXIBLE_ARRAY_MEMBER]
Definition: logtape.c:188
BufFile * pfile
Definition: logtape.c:154
void BufFileClose(BufFile *file)
Definition: buffile.c:397
long * freeBlocks
Definition: logtape.c:182
void pfree(void *pointer)
Definition: mcxt.c:936
char * buffer
Definition: logtape.c:140
int i

◆ LogicalTapeSetCreate()

LogicalTapeSet* LogicalTapeSetCreate ( int  ntapes)

Definition at line 379 of file logtape.c.

References Assert, LogicalTapeSet::blocksSorted, LogicalTape::buffer, LogicalTape::buffer_size, BufFileCreateTemp(), LogicalTape::curBlockNumber, LogicalTape::dirty, LogicalTape::firstBlockNumber, LogicalTapeSet::forgetFreeSpace, LogicalTapeSet::freeBlocks, LogicalTapeSet::freeBlocksLen, LogicalTape::frozen, i, LogicalTapeSet::nBlocksAllocated, LogicalTapeSet::nBlocksWritten, LogicalTape::nbytes, LogicalTapeSet::nFreeBlocks, LogicalTapeSet::nTapes, offsetof, palloc(), LogicalTapeSet::pfile, LogicalTape::pos, LogicalTapeSet::tapes, and LogicalTape::writing.

Referenced by inittapes().

380 {
381  LogicalTapeSet *lts;
382  LogicalTape *lt;
383  int i;
384 
385  /*
386  * Create top-level struct including per-tape LogicalTape structs.
387  */
388  Assert(ntapes > 0);
389  lts = (LogicalTapeSet *) palloc(offsetof(LogicalTapeSet, tapes) +
390  ntapes * sizeof(LogicalTape));
391  lts->pfile = BufFileCreateTemp(false);
392  lts->nBlocksAllocated = 0L;
393  lts->nBlocksWritten = 0L;
394  lts->forgetFreeSpace = false;
395  lts->blocksSorted = true; /* a zero-length array is sorted ... */
396  lts->freeBlocksLen = 32; /* reasonable initial guess */
397  lts->freeBlocks = (long *) palloc(lts->freeBlocksLen * sizeof(long));
398  lts->nFreeBlocks = 0;
399  lts->nTapes = ntapes;
400 
401  /*
402  * Initialize per-tape structs. Note we allocate the I/O buffer and the
403  * first block for a tape only when it is first actually written to. This
404  * avoids wasting memory space when tuplesort.c overestimates the number
405  * of tapes needed.
406  */
407  for (i = 0; i < ntapes; i++)
408  {
409  lt = &lts->tapes[i];
410  lt->writing = true;
411  lt->frozen = false;
412  lt->dirty = false;
413  lt->firstBlockNumber = -1L;
414  lt->curBlockNumber = -1L;
415  lt->buffer = NULL;
416  lt->buffer_size = 0;
417  lt->pos = 0;
418  lt->nbytes = 0;
419  }
420  return lts;
421 }
LogicalTape tapes[FLEXIBLE_ARRAY_MEMBER]
Definition: logtape.c:188
int nFreeBlocks
Definition: logtape.c:183
long nBlocksWritten
Definition: logtape.c:165
int freeBlocksLen
Definition: logtape.c:184
BufFile * pfile
Definition: logtape.c:154
bool frozen
Definition: logtape.c:122
bool writing
Definition: logtape.c:121
long * freeBlocks
Definition: logtape.c:182
bool dirty
Definition: logtape.c:123
BufFile * BufFileCreateTemp(bool interXact)
Definition: buffile.c:182
int nbytes
Definition: logtape.c:143
long firstBlockNumber
Definition: logtape.c:133
long curBlockNumber
Definition: logtape.c:134
#define Assert(condition)
Definition: c.h:680
char * buffer
Definition: logtape.c:140
void * palloc(Size size)
Definition: mcxt.c:835
bool forgetFreeSpace
Definition: logtape.c:180
int i
struct LogicalTape LogicalTape
bool blocksSorted
Definition: logtape.c:181
long nBlocksAllocated
Definition: logtape.c:164
int buffer_size
Definition: logtape.c:141
#define offsetof(type, field)
Definition: c.h:603

◆ LogicalTapeSetForgetFreeSpace()

void LogicalTapeSetForgetFreeSpace ( LogicalTapeSet lts)

Definition at line 453 of file logtape.c.

References LogicalTapeSet::forgetFreeSpace.

Referenced by mergeruns().

454 {
455  lts->forgetFreeSpace = true;
456 }
bool forgetFreeSpace
Definition: logtape.c:180

◆ LogicalTapeTell()

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

Definition at line 870 of file logtape.c.

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

Referenced by tuplesort_markpos().

872 {
873  LogicalTape *lt;
874 
875  Assert(tapenum >= 0 && tapenum < lts->nTapes);
876  lt = &lts->tapes[tapenum];
877 
878  /* With a larger buffer, 'pos' wouldn't be the same as offset within page */
879  Assert(lt->buffer_size == BLCKSZ);
880 
881  *blocknum = lt->curBlockNumber;
882  *offset = lt->pos;
883 }
LogicalTape tapes[FLEXIBLE_ARRAY_MEMBER]
Definition: logtape.c:188
long curBlockNumber
Definition: logtape.c:134
#define Assert(condition)
Definition: c.h:680
int buffer_size
Definition: logtape.c:141

◆ LogicalTapeWrite()

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

Definition at line 464 of file logtape.c.

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

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

466 {
467  LogicalTape *lt;
468  size_t nthistime;
469 
470  Assert(tapenum >= 0 && tapenum < lts->nTapes);
471  lt = &lts->tapes[tapenum];
472  Assert(lt->writing);
473 
474  /* Allocate data buffer and first block on first write */
475  if (lt->buffer == NULL)
476  {
477  lt->buffer = (char *) palloc(BLCKSZ);
478  lt->buffer_size = BLCKSZ;
479  }
480  if (lt->curBlockNumber == -1)
481  {
482  Assert(lt->firstBlockNumber == -1);
483  Assert(lt->pos == 0);
484 
485  lt->curBlockNumber = ltsGetFreeBlock(lts);
487 
488  TapeBlockGetTrailer(lt->buffer)->prev = -1L;
489  }
490 
491  Assert(lt->buffer_size == BLCKSZ);
492  while (size > 0)
493  {
494  if (lt->pos >= TapeBlockPayloadSize)
495  {
496  /* Buffer full, dump it out */
497  long nextBlockNumber;
498 
499  if (!lt->dirty)
500  {
501  /* Hmm, went directly from reading to writing? */
502  elog(ERROR, "invalid logtape state: should be dirty");
503  }
504 
505  /*
506  * First allocate the next block, so that we can store it in the
507  * 'next' pointer of this block.
508  */
509  nextBlockNumber = ltsGetFreeBlock(lts);
510 
511  /* set the next-pointer and dump the current block. */
512  TapeBlockGetTrailer(lt->buffer)->next = nextBlockNumber;
513  ltsWriteBlock(lts, lt->curBlockNumber, (void *) lt->buffer);
514 
515  /* initialize the prev-pointer of the next block */
516  TapeBlockGetTrailer(lt->buffer)->prev = lt->curBlockNumber;
517  lt->curBlockNumber = nextBlockNumber;
518  lt->pos = 0;
519  lt->nbytes = 0;
520  }
521 
522  nthistime = TapeBlockPayloadSize - lt->pos;
523  if (nthistime > size)
524  nthistime = size;
525  Assert(nthistime > 0);
526 
527  memcpy(lt->buffer + lt->pos, ptr, nthistime);
528 
529  lt->dirty = true;
530  lt->pos += nthistime;
531  if (lt->nbytes < lt->pos)
532  lt->nbytes = lt->pos;
533  ptr = (void *) ((char *) ptr + nthistime);
534  size -= nthistime;
535  }
536 }
LogicalTape tapes[FLEXIBLE_ARRAY_MEMBER]
Definition: logtape.c:188
#define TapeBlockPayloadSize
Definition: logtape.c:97
static long ltsGetFreeBlock(LogicalTapeSet *lts)
Definition: logtape.c:318
bool writing
Definition: logtape.c:121
bool dirty
Definition: logtape.c:123
#define ERROR
Definition: elog.h:43
int nbytes
Definition: logtape.c:143
long firstBlockNumber
Definition: logtape.c:133
long curBlockNumber
Definition: logtape.c:134
#define Assert(condition)
Definition: c.h:680
char * buffer
Definition: logtape.c:140
void * palloc(Size size)
Definition: mcxt.c:835
#define elog
Definition: elog.h:219
int buffer_size
Definition: logtape.c:141
static void ltsWriteBlock(LogicalTapeSet *lts, long blocknum, void *buffer)
Definition: logtape.c:203
#define TapeBlockGetTrailer(buf)
Definition: logtape.c:98

◆ ltsGetFreeBlock()

static long ltsGetFreeBlock ( LogicalTapeSet lts)
static

Definition at line 318 of file logtape.c.

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

Referenced by LogicalTapeWrite().

319 {
320  /*
321  * If there are multiple free blocks, we select the one appearing last in
322  * freeBlocks[] (after sorting the array if needed). If there are none,
323  * assign the next block at the end of the file.
324  */
325  if (lts->nFreeBlocks > 0)
326  {
327  if (!lts->blocksSorted)
328  {
329  qsort((void *) lts->freeBlocks, lts->nFreeBlocks,
330  sizeof(long), freeBlocks_cmp);
331  lts->blocksSorted = true;
332  }
333  return lts->freeBlocks[--lts->nFreeBlocks];
334  }
335  else
336  return lts->nBlocksAllocated++;
337 }
int nFreeBlocks
Definition: logtape.c:183
long * freeBlocks
Definition: logtape.c:182
static int freeBlocks_cmp(const void *a, const void *b)
Definition: logtape.c:301
#define qsort(a, b, c, d)
Definition: port.h:408
bool blocksSorted
Definition: logtape.c:181
long nBlocksAllocated
Definition: logtape.c:164

◆ ltsReadBlock()

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

Definition at line 246 of file logtape.c.

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

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

247 {
248  if (BufFileSeekBlock(lts->pfile, blocknum) != 0 ||
249  BufFileRead(lts->pfile, buffer, BLCKSZ) != BLCKSZ)
250  ereport(ERROR,
252  errmsg("could not read block %ld of temporary file: %m",
253  blocknum)));
254 }
BufFile * pfile
Definition: logtape.c:154
#define ERROR
Definition: elog.h:43
int errcode_for_file_access(void)
Definition: elog.c:598
#define ereport(elevel, rest)
Definition: elog.h:122
int BufFileSeekBlock(BufFile *file, long blknum)
Definition: buffile.c:778
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:214
int errmsg(const char *fmt,...)
Definition: elog.c:797
size_t BufFileRead(BufFile *file, void *ptr, size_t size)
Definition: buffile.c:554

◆ ltsReadFillBuffer()

static bool ltsReadFillBuffer ( LogicalTapeSet lts,
LogicalTape lt 
)
static

Definition at line 262 of file logtape.c.

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

Referenced by LogicalTapeRead(), and LogicalTapeRewindForRead().

263 {
264  lt->pos = 0;
265  lt->nbytes = 0;
266 
267  do
268  {
269  char *thisbuf = lt->buffer + lt->nbytes;
270 
271  /* Fetch next block number */
272  if (lt->nextBlockNumber == -1L)
273  break; /* EOF */
274 
275  /* Read the block */
276  ltsReadBlock(lts, lt->nextBlockNumber, (void *) thisbuf);
277  if (!lt->frozen)
280 
281  lt->nbytes += TapeBlockGetNBytes(thisbuf);
282  if (TapeBlockIsLast(thisbuf))
283  {
284  lt->nextBlockNumber = -1L;
285  /* EOF */
286  break;
287  }
288  else
289  lt->nextBlockNumber = TapeBlockGetTrailer(thisbuf)->next;
290 
291  /* Advance to next block, if we have buffer space left */
292  } while (lt->buffer_size - lt->nbytes > BLCKSZ);
293 
294  return (lt->nbytes > 0);
295 }
#define TapeBlockIsLast(buf)
Definition: logtape.c:101
static void ltsReleaseBlock(LogicalTapeSet *lts, long blocknum)
Definition: logtape.c:343
bool frozen
Definition: logtape.c:122
long nextBlockNumber
Definition: logtape.c:135
int nbytes
Definition: logtape.c:143
long curBlockNumber
Definition: logtape.c:134
#define TapeBlockGetNBytes(buf)
Definition: logtape.c:102
char * buffer
Definition: logtape.c:140
int buffer_size
Definition: logtape.c:141
#define TapeBlockGetTrailer(buf)
Definition: logtape.c:98
static void ltsReadBlock(LogicalTapeSet *lts, long blocknum, void *buffer)
Definition: logtape.c:246

◆ ltsReleaseBlock()

static void ltsReleaseBlock ( LogicalTapeSet lts,
long  blocknum 
)
static

Definition at line 343 of file logtape.c.

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

Referenced by ltsReadFillBuffer().

344 {
345  int ndx;
346 
347  /*
348  * Do nothing if we're no longer interested in remembering free space.
349  */
350  if (lts->forgetFreeSpace)
351  return;
352 
353  /*
354  * Enlarge freeBlocks array if full.
355  */
356  if (lts->nFreeBlocks >= lts->freeBlocksLen)
357  {
358  lts->freeBlocksLen *= 2;
359  lts->freeBlocks = (long *) repalloc(lts->freeBlocks,
360  lts->freeBlocksLen * sizeof(long));
361  }
362 
363  /*
364  * Add blocknum to array, and mark the array unsorted if it's no longer in
365  * decreasing order.
366  */
367  ndx = lts->nFreeBlocks++;
368  lts->freeBlocks[ndx] = blocknum;
369  if (ndx > 0 && lts->freeBlocks[ndx - 1] < blocknum)
370  lts->blocksSorted = false;
371 }
int nFreeBlocks
Definition: logtape.c:183
int freeBlocksLen
Definition: logtape.c:184
long * freeBlocks
Definition: logtape.c:182
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:949
bool forgetFreeSpace
Definition: logtape.c:180
bool blocksSorted
Definition: logtape.c:181

◆ ltsWriteBlock()

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

Definition at line 203 of file logtape.c.

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

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

204 {
205  /*
206  * BufFile does not support "holes", so if we're about to write a block
207  * that's past the current end of file, fill the space between the current
208  * end of file and the target block with zeros.
209  *
210  * This should happen rarely, otherwise you are not writing very
211  * sequentially. In current use, this only happens when the sort ends
212  * writing a run, and switches to another tape. The last block of the
213  * previous tape isn't flushed to disk until the end of the sort, so you
214  * get one-block hole, where the last block of the previous tape will
215  * later go.
216  */
217  while (blocknum > lts->nBlocksWritten)
218  {
219  char zerobuf[BLCKSZ];
220 
221  MemSet(zerobuf, 0, sizeof(zerobuf));
222 
223  ltsWriteBlock(lts, lts->nBlocksWritten, zerobuf);
224  }
225 
226  /* Write the requested block */
227  if (BufFileSeekBlock(lts->pfile, blocknum) != 0 ||
228  BufFileWrite(lts->pfile, buffer, BLCKSZ) != BLCKSZ)
229  ereport(ERROR,
231  errmsg("could not write block %ld of temporary file: %m",
232  blocknum)));
233 
234  /* Update nBlocksWritten, if we extended the file */
235  if (blocknum == lts->nBlocksWritten)
236  lts->nBlocksWritten++;
237 }
long nBlocksWritten
Definition: logtape.c:165
BufFile * pfile
Definition: logtape.c:154
#define MemSet(start, val, len)
Definition: c.h:863
#define ERROR
Definition: elog.h:43
int errcode_for_file_access(void)
Definition: elog.c:598
#define ereport(elevel, rest)
Definition: elog.h:122
int BufFileSeekBlock(BufFile *file, long blknum)
Definition: buffile.c:778
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:214
int errmsg(const char *fmt,...)
Definition: elog.c:797
size_t BufFileWrite(BufFile *file, void *ptr, size_t size)
Definition: buffile.c:601
static void ltsWriteBlock(LogicalTapeSet *lts, long blocknum, void *buffer)
Definition: logtape.c:203