From: Tom Lane Date: Sun, 17 Oct 1999 22:19:07 +0000 (+0000) Subject: Remove now-dead sort modules. X-Git-Tag: REL7_0~1296 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=887afac1f59e2b69a8bbbdac6d13ff288042e855;p=postgresql Remove now-dead sort modules. --- diff --git a/src/backend/utils/sort/lselect.c b/src/backend/utils/sort/lselect.c deleted file mode 100644 index 7f521b821f..0000000000 --- a/src/backend/utils/sort/lselect.c +++ /dev/null @@ -1,355 +0,0 @@ -/*------------------------------------------------------------------------- - * - * lselect.c - * leftist tree selection algorithm (linked priority queue--Knuth, Vol.3, - * pp.150-52) - * - * Copyright (c) 1994, Regents of the University of California - * - * - * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/sort/Attic/lselect.c,v 1.19 1999/07/17 20:18:16 momjian Exp $ - * - *------------------------------------------------------------------------- - */ - -#include "postgres.h" - - -#include "access/heapam.h" -#include "utils/lselect.h" - -/* - * lmerge - merges two leftist trees into one - * - * Note: - * Enforcing the rule that pt->lt_dist >= qt->lt_dist may - * simplifify much of the code. Removing recursion will not - * speed up code significantly. - */ -struct leftist * -lmerge(struct leftist * pt, struct leftist * qt, LeftistContext context) -{ - struct leftist *root, - *majorLeftist, - *minorLeftist; - int dist; - - if (tuplecmp(pt->lt_tuple, qt->lt_tuple, context)) - { - root = pt; - majorLeftist = qt; - } - else - { - root = qt; - majorLeftist = pt; - } - if (root->lt_left == NULL) - root->lt_left = majorLeftist; - else - { - if ((minorLeftist = root->lt_right) != NULL) - majorLeftist = lmerge(majorLeftist, minorLeftist, context); - if ((dist = root->lt_left->lt_dist) < majorLeftist->lt_dist) - { - root->lt_dist = 1 + dist; - root->lt_right = root->lt_left; - root->lt_left = majorLeftist; - } - else - { - root->lt_dist = 1 + majorLeftist->lt_dist; - root->lt_right = majorLeftist; - } - } - return root; -} - -static struct leftist * -linsert(struct leftist * root, struct leftist * new1, LeftistContext context) -{ - struct leftist *left, - *right; - - if (!tuplecmp(root->lt_tuple, new1->lt_tuple, context)) - { - new1->lt_left = root; - return new1; - } - left = root->lt_left; - right = root->lt_right; - if (right == NULL) - { - if (left == NULL) - root->lt_left = new1; - else - { - root->lt_right = new1; - root->lt_dist = 2; - } - return root; - } - right = linsert(right, new1, context); - if (right->lt_dist < left->lt_dist) - { - root->lt_dist = 1 + left->lt_dist; - root->lt_left = right; - root->lt_right = left; - } - else - { - root->lt_dist = 1 + right->lt_dist; - root->lt_right = right; - } - return root; -} - -/* - * gettuple - returns tuple at top of tree (Tuples) - * - * Returns: - * tuple at top of tree, NULL if failed ALLOC() - * *devnum is set to the devnum of tuple returned - * *treep is set to the new tree - * - * Note: - * *treep must not be NULL - * NULL is currently never returned BUG - */ -HeapTuple -gettuple(struct leftist ** treep, - short *devnum, /* device from which tuple came */ - LeftistContext context) -{ - struct leftist *tp; - HeapTuple tup; - - tp = *treep; - tup = tp->lt_tuple; - *devnum = tp->lt_devnum; - if (tp->lt_dist == 1) /* lt_left == NULL */ - *treep = tp->lt_left; - else - *treep = lmerge(tp->lt_left, tp->lt_right, context); - - pfree(tp); - return tup; -} - -/* - * puttuple - inserts new tuple into tree - * - * Returns: - * NULL iff failed ALLOC() - * - * Note: - * Currently never returns NULL BUG - */ -void -puttuple(struct leftist ** treep, - HeapTuple newtuple, - short devnum, - LeftistContext context) -{ - struct leftist *new1; - struct leftist *tp; - - new1 = (struct leftist *) palloc((unsigned) sizeof(struct leftist)); - new1->lt_dist = 1; - new1->lt_devnum = devnum; - new1->lt_tuple = newtuple; - new1->lt_left = NULL; - new1->lt_right = NULL; - if ((tp = *treep) == NULL) - *treep = new1; - else - *treep = linsert(tp, new1, context); - return; -} - - -/* - * tuplecmp - Compares two tuples with respect CmpList - * - * Returns: - * 1 if left < right ;0 otherwise - * Assumtions: - */ -int -tuplecmp(HeapTuple ltup, HeapTuple rtup, LeftistContext context) -{ - int nkey; - int result = 0; - - if (ltup == (HeapTuple) NULL) - return 0; - if (rtup == (HeapTuple) NULL) - return 1; - for (nkey = 0; nkey < context->nKeys; nkey++) - { - ScanKey thisKey = & context->scanKeys[nkey]; - Datum lattr, - rattr; - bool lisnull, - risnull; - - lattr = heap_getattr(ltup, thisKey->sk_attno, - context->tupDesc, &lisnull); - rattr = heap_getattr(rtup, thisKey->sk_attno, - context->tupDesc, &risnull); - if (lisnull) - { - if (risnull) - continue; /* treat two nulls as equal */ - return 0; /* else, a null sorts after all else */ - } - if (risnull) - return 1; - if (thisKey->sk_flags & SK_COMMUTE) - { - if (!(result = - (long) (*fmgr_faddr(&thisKey->sk_func)) (rattr, lattr))) - result = - -(long) (*fmgr_faddr(&thisKey->sk_func)) (lattr, rattr); - } - else - { - if (!(result = - (long) (*fmgr_faddr(&thisKey->sk_func)) (lattr, rattr))) - result = - -(long) (*fmgr_faddr(&thisKey->sk_func)) (rattr, lattr); - } - if (result) - break; - } - return result == 1; -} - -#ifdef EBUG -void -checktree(struct leftist * tree, LeftistContext context) -{ - int lnodes; - int rnodes; - - if (tree == NULL) - { - puts("Null tree."); - return; - } - lnodes = checktreer(tree->lt_left, 1, context); - rnodes = checktreer(tree->lt_right, 1, context); - if (lnodes < 0) - { - lnodes = -lnodes; - puts("0:\tBad left side."); - } - if (rnodes < 0) - { - rnodes = -rnodes; - puts("0:\tBad right side."); - } - if (lnodes == 0) - { - if (rnodes != 0) - puts("0:\tLeft and right reversed."); - if (tree->lt_dist != 1) - puts("0:\tDistance incorrect."); - } - else if (rnodes == 0) - { - if (tree->lt_dist != 1) - puts("0:\tDistance incorrect."); - } - else if (tree->lt_left->lt_dist < tree->lt_right->lt_dist) - { - puts("0:\tLeft and right reversed."); - if (tree->lt_dist != 1 + tree->lt_left->lt_dist) - puts("0:\tDistance incorrect."); - } - else if (tree->lt_dist != 1 + tree->lt_right->lt_dist) - puts("0:\tDistance incorrect."); - if (lnodes > 0) - if (tuplecmp(tree->lt_left->lt_tuple, tree->lt_tuple, context)) - printf("%d:\tLeft child < parent.\n"); - if (rnodes > 0) - if (tuplecmp(tree->lt_right->lt_tuple, tree->lt_tuple, context)) - printf("%d:\tRight child < parent.\n"); - printf("Tree has %d nodes\n", 1 + lnodes + rnodes); -} - -int -checktreer(struct leftist * tree, int level, LeftistContext context) -{ - int lnodes, - rnodes; - int error = 0; - - if (tree == NULL) - return 0; - lnodes = checktreer(tree->lt_left, level + 1, context); - rnodes = checktreer(tree->lt_right, level + 1, context); - if (lnodes < 0) - { - error = 1; - lnodes = -lnodes; - printf("%d:\tBad left side.\n", level); - } - if (rnodes < 0) - { - error = 1; - rnodes = -rnodes; - printf("%d:\tBad right side.\n", level); - } - if (lnodes == 0) - { - if (rnodes != 0) - { - error = 1; - printf("%d:\tLeft and right reversed.\n", level); - } - if (tree->lt_dist != 1) - { - error = 1; - printf("%d:\tDistance incorrect.\n", level); - } - } - else if (rnodes == 0) - { - if (tree->lt_dist != 1) - { - error = 1; - printf("%d:\tDistance incorrect.\n", level); - } - } - else if (tree->lt_left->lt_dist < tree->lt_right->lt_dist) - { - error = 1; - printf("%d:\tLeft and right reversed.\n", level); - if (tree->lt_dist != 1 + tree->lt_left->lt_dist) - printf("%d:\tDistance incorrect.\n", level); - } - else if (tree->lt_dist != 1 + tree->lt_right->lt_dist) - { - error = 1; - printf("%d:\tDistance incorrect.\n", level); - } - if (lnodes > 0) - if (tuplecmp(tree->lt_left->lt_tuple, tree->lt_tuple, context)) - { - error = 1; - printf("%d:\tLeft child < parent.\n"); - } - if (rnodes > 0) - if (tuplecmp(tree->lt_right->lt_tuple, tree->lt_tuple, context)) - { - error = 1; - printf("%d:\tRight child < parent.\n"); - } - if (error) - return -1 + -lnodes + -rnodes; - return 1 + lnodes + rnodes; -} - -#endif diff --git a/src/backend/utils/sort/psort.c b/src/backend/utils/sort/psort.c deleted file mode 100644 index 67cdfc292e..0000000000 --- a/src/backend/utils/sort/psort.c +++ /dev/null @@ -1,1025 +0,0 @@ -/*------------------------------------------------------------------------- - * - * psort.c - * Polyphase merge sort. - * - * See Knuth, volume 3, for more than you want to know about this algorithm. - * - * NOTES - * - * This needs to be generalized to handle index tuples as well as heap tuples, - * so that the near-duplicate code in nbtsort.c can be eliminated. Also, - * I think it's got memory leak problems. - * - * Copyright (c) 1994, Regents of the University of California - * - * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/sort/Attic/psort.c,v 1.58 1999/10/16 19:49:27 tgl Exp $ - * - *------------------------------------------------------------------------- - */ - -#include - -#include "postgres.h" - -#include "access/heapam.h" -#include "access/relscan.h" -#include "executor/execdebug.h" -#include "executor/executor.h" -#include "miscadmin.h" -#include "utils/logtape.h" -#include "utils/lselect.h" -#include "utils/psort.h" - -#define MAXTAPES 7 /* See Knuth Fig. 70, p273 */ - -struct tape -{ - int tp_dummy; /* (D) */ - int tp_fib; /* (A) */ - int tp_tapenum; /* (TAPE) */ - struct tape *tp_prev; -}; - -/* - * Private state of a Psort operation. The "psortstate" field in a Sort node - * points to one of these. This replaces a lot of global variables that used - * to be here... - */ -typedef struct Psortstate -{ - LeftistContextData treeContext; - - int TapeRange; /* number of tapes less 1 (T) */ - int Level; /* Knuth's l */ - int TotalDummy; /* sum of tp_dummy across all tapes */ - struct tape Tape[MAXTAPES]; - - LogicalTapeSet *tapeset; /* logtape.c object for tapes in a temp file */ - - int BytesRead; /* I/O statistics (useless) */ - int BytesWritten; - int tupcount; - - struct leftist *Tuples; /* current tuple tree */ - - int psort_grab_tape; /* tape number of finished output data */ - long psort_current; /* array index (only used if not tape) */ - /* psort_saved(_offset) holds marked position for mark and restore */ - long psort_saved; /* could be tape block#, or array index */ - int psort_saved_offset; /* lower bits of psort_saved, if tape */ - bool using_tape_files; - bool all_fetched; /* this is for cursors */ - - HeapTuple *memtuples; -} Psortstate; - -/* - * PS - Macro to access and cast psortstate from a Sort node - */ -#define PS(N) ((Psortstate *)(N)->psortstate) - -static bool createfirstrun(Sort *node); -static bool createrun(Sort *node, int desttapenum); -static void dumptuples(Sort *node, int desttapenum); -static void initialrun(Sort *node); -static void inittapes(Sort *node); -static void merge(Sort *node, struct tape * dest); -static int mergeruns(Sort *node); -static int _psort_cmp(HeapTuple *ltup, HeapTuple *rtup); - -/* these are used by _psort_cmp, and are set just before calling qsort() */ -static TupleDesc PsortTupDesc; -static ScanKey PsortKeys; -static int PsortNkeys; - -/* - * tlenzero is used to write a zero to delimit runs, tlendummy is used - * to read in length words that we don't care about. - * - * both vars must have the same size as HeapTuple->t_len - */ -static unsigned int tlenzero = 0; -static unsigned int tlendummy; - - -/* - * psort_begin - * - * polyphase merge sort entry point. Sorts the subplan - * into memory or a temporary file. After - * this is called, calling the interface function - * psort_grabtuple iteratively will get you the sorted - * tuples. psort_end releases storage when done. - * - * Allocates and initializes sort node's psort state. - */ -bool -psort_begin(Sort *node, int nkeys, ScanKey key) -{ - AssertArg(nkeys >= 1); - AssertArg(key[0].sk_attno != 0); - AssertArg(key[0].sk_procedure != 0); - - node->psortstate = (void *) palloc(sizeof(struct Psortstate)); - - PS(node)->treeContext.tupDesc = ExecGetTupType(outerPlan((Plan *) node)); - PS(node)->treeContext.nKeys = nkeys; - PS(node)->treeContext.scanKeys = key; - PS(node)->treeContext.sortMem = SortMem * 1024; - - PS(node)->tapeset = NULL; - - PS(node)->BytesRead = 0; - PS(node)->BytesWritten = 0; - PS(node)->tupcount = 0; - - PS(node)->Tuples = NULL; - - PS(node)->using_tape_files = false; - PS(node)->all_fetched = false; - PS(node)->psort_grab_tape = -1; - - PS(node)->memtuples = NULL; - - initialrun(node); - - if (PS(node)->tupcount == 0) - return false; - - if (PS(node)->using_tape_files && PS(node)->psort_grab_tape == -1) - PS(node)->psort_grab_tape = mergeruns(node); - - PS(node)->psort_current = 0L; - PS(node)->psort_saved = 0L; - PS(node)->psort_saved_offset = 0; - - return true; -} - -/* - * inittapes - initializes the tapes - * - (polyphase merge Alg.D(D1)--Knuth, Vol.3, p.270) - * - * This is called only if we have found we don't have room to sort in memory. - */ -static void -inittapes(Sort *node) -{ - int i; - struct tape *tp; - - Assert(node != (Sort *) NULL); - Assert(PS(node) != (Psortstate *) NULL); - - PS(node)->tapeset = LogicalTapeSetCreate(MAXTAPES); - - tp = PS(node)->Tape; - for (i = 0; i < MAXTAPES; i++) - { - tp->tp_dummy = 1; - tp->tp_fib = 1; - tp->tp_tapenum = i; - tp->tp_prev = tp - 1; - tp++; - } - PS(node)->TapeRange = --tp - PS(node)->Tape; - tp->tp_dummy = 0; - tp->tp_fib = 0; - PS(node)->Tape[0].tp_prev = tp; - - PS(node)->Level = 1; - PS(node)->TotalDummy = PS(node)->TapeRange; - - PS(node)->using_tape_files = true; -} - -/* - * PUTTUP - writes the next tuple - * ENDRUN - mark end of run - * TRYGETLEN - reads the length of the next tuple, if any - * GETLEN - reads the length of the next tuple, must be one - * ALLOCTUP - returns space for the new tuple - * GETTUP - reads the tuple - * - * Note: - * LEN field must be as HeapTuple->t_len; FP is a stream - */ - - -#define PUTTUP(NODE, TUP, TAPE) \ -( \ - (TUP)->t_len += HEAPTUPLESIZE, \ - PS(NODE)->BytesWritten += (TUP)->t_len, \ - LogicalTapeWrite(PS(NODE)->tapeset, (TAPE), (void*)(TUP), (TUP)->t_len), \ - LogicalTapeWrite(PS(NODE)->tapeset, (TAPE), (void*)&((TUP)->t_len), sizeof(tlendummy)), \ - (TUP)->t_len -= HEAPTUPLESIZE \ -) - -#define ENDRUN(NODE, TAPE) \ - LogicalTapeWrite(PS(NODE)->tapeset, (TAPE), (void *)&tlenzero, sizeof(tlenzero)) - -#define TRYGETLEN(NODE, LEN, TAPE) \ - (LogicalTapeRead(PS(NODE)->tapeset, (TAPE), \ - (void *) &(LEN), sizeof(tlenzero)) == sizeof(tlenzero) \ - && (LEN) != 0) - -#define GETLEN(NODE, LEN, TAPE) \ - do { \ - if (! TRYGETLEN(NODE, LEN, TAPE)) \ - elog(ERROR, "psort: unexpected end of data"); \ - } while(0) - -static void GETTUP(Sort *node, HeapTuple tup, unsigned int len, int tape) -{ - IncrProcessed(); - PS(node)->BytesRead += len; - if (LogicalTapeRead(PS(node)->tapeset, tape, - ((char *) tup) + sizeof(tlenzero), - len - sizeof(tlenzero)) != len - sizeof(tlenzero)) - elog(ERROR, "psort: unexpected end of data"); - tup->t_len = len - HEAPTUPLESIZE; - tup->t_data = (HeapTupleHeader) ((char *) tup + HEAPTUPLESIZE); - if (LogicalTapeRead(PS(node)->tapeset, tape, - (void *) &tlendummy, - sizeof(tlendummy)) != sizeof(tlendummy)) - elog(ERROR, "psort: unexpected end of data"); -} - -#define ALLOCTUP(LEN) ((HeapTuple) palloc(LEN)) -#define FREE(x) pfree((char *) (x)) - - /* - * USEMEM - record use of memory FREEMEM - record - * freeing of memory FULLMEM - 1 iff a tuple will fit - */ - -#define USEMEM(NODE,AMT) PS(node)->treeContext.sortMem -= (AMT) -#define FREEMEM(NODE,AMT) PS(node)->treeContext.sortMem += (AMT) -#define LACKMEM(NODE) (PS(node)->treeContext.sortMem <= BLCKSZ) /* not accurate */ -#define TRACEMEM(FUNC) -#define TRACEOUT(FUNC, TUP) - -/* - * initialrun - distributes tuples from the relation - * - (replacement selection(R2-R3)--Knuth, Vol.3, p.257) - * - (polyphase merge Alg.D(D2-D4)--Knuth, Vol.3, p.271) - * - * Explanation: - * Tuples are distributed to the tapes as in Algorithm D. - * A "tuple" with t_size == 0 is used to mark the end of a run. - * - * Note: - * The replacement selection algorithm has been modified - * to go from R1 directly to R3 skipping R2 the first time. - * - * Maybe should use closer(rdesc) before return - * Perhaps should adjust the number of tapes if less than n. - * used--v. likely to have problems in mergeruns(). - * Must know if should open/close files before each - * call to psort()? If should--messy?? - * - * Possible optimization: - * put the first xxx runs in quickly--problem here since - * I (perhaps prematurely) combined the 2 algorithms. - * Also, perhaps allocate tapes when needed. Split into 2 funcs. - */ -static void -initialrun(Sort *node) -{ - struct tape *tp; - int baseruns; /* D:(a) */ - int extrapasses; /* EOF */ - int tapenum; - - Assert(node != (Sort *) NULL); - Assert(PS(node) != (Psortstate *) NULL); - - tp = PS(node)->Tape; - - if (createfirstrun(node)) - { - Assert(PS(node)->using_tape_files); - extrapasses = 0; - } - else - { - /* all tuples fetched */ - if (!PS(node)->using_tape_files) /* empty or sorted in - * memory */ - return; - - /* - * if PS(node)->Tuples == NULL then we have single (sorted) run - * which can be used as result grab file! So, we may avoid - * mergeruns - it will just copy this run to new file. - */ - if (PS(node)->Tuples == NULL) - { - PS(node)->psort_grab_tape = PS(node)->Tape[0].tp_tapenum; - /* freeze and rewind the finished output tape */ - LogicalTapeFreeze(PS(node)->tapeset, PS(node)->psort_grab_tape); - return; - } - extrapasses = 2; - } - - for (;;) - { - tp->tp_dummy--; - PS(node)->TotalDummy--; - if (tp->tp_dummy < (tp + 1)->tp_dummy) - tp++; - else - { - if (tp->tp_dummy != 0) - tp = PS(node)->Tape; - else - { - PS(node)->Level++; - baseruns = PS(node)->Tape[0].tp_fib; - for (tp = PS(node)->Tape; - tp - PS(node)->Tape < PS(node)->TapeRange; tp++) - { - PS(node)->TotalDummy += (tp->tp_dummy = baseruns - + (tp + 1)->tp_fib - - tp->tp_fib); - tp->tp_fib = baseruns - + (tp + 1)->tp_fib; - } - tp = PS(node)->Tape; /* D4 */ - } /* D3 */ - } - if (extrapasses) - { - if (--extrapasses) - { - dumptuples(node, tp->tp_tapenum); - ENDRUN(node, tp->tp_tapenum); - continue; - } - else - break; - } - if (createrun(node, tp->tp_tapenum) == false) - extrapasses = 1 + (PS(node)->Tuples != NULL); - /* D2 */ - } - /* End of step D2: rewind all output tapes to prepare for merging */ - for (tapenum = 0; tapenum < PS(node)->TapeRange; tapenum++) - LogicalTapeRewind(PS(node)->tapeset, tapenum, false); -} - -/* - * createfirstrun - tries to sort tuples in memory using qsort - * until LACKMEM; if not enough memory then switches - * to tape method - * - * Returns: - * FALSE iff process through end of relation - * Tuples contains the tuples for the following run upon exit - */ -static bool -createfirstrun(Sort *node) -{ - HeapTuple tup; - bool foundeor = false; - HeapTuple *memtuples; - int t_last = -1; - int t_free = 1000; - TupleTableSlot *cr_slot; - - Assert(node != (Sort *) NULL); - Assert(PS(node) != (Psortstate *) NULL); - Assert(!PS(node)->using_tape_files); - Assert(PS(node)->memtuples == NULL); - Assert(PS(node)->tupcount == 0); - if (LACKMEM(node)) - elog(ERROR, "psort: LACKMEM before createfirstrun"); - - memtuples = palloc(t_free * sizeof(HeapTuple)); - - for (;;) - { - if (LACKMEM(node)) - break; - - /* - * About to call ExecProcNode, it can mess up the state if it - * eventually calls another Sort node. So must stow it away here - * for the meantime. -Rex - * 2.2.1995 - */ - - cr_slot = ExecProcNode(outerPlan((Plan *) node), (Plan *) node); - - if (TupIsNull(cr_slot)) - { - foundeor = true; - break; - } - - tup = heap_copytuple(cr_slot->val); - ExecClearTuple(cr_slot); - - IncrProcessed(); - USEMEM(node, tup->t_len); - TRACEMEM(createfirstrun); - if (t_free <= 0) - { - t_free = 1000; - memtuples = repalloc(memtuples, - (t_last + t_free + 1) * sizeof(HeapTuple)); - } - t_last++; - t_free--; - memtuples[t_last] = tup; - } - - if (t_last < 0) /* empty */ - { - Assert(foundeor); - pfree(memtuples); - return false; - } - t_last++; - PS(node)->tupcount = t_last; - PsortTupDesc = PS(node)->treeContext.tupDesc; - PsortKeys = PS(node)->treeContext.scanKeys; - PsortNkeys = PS(node)->treeContext.nKeys; - qsort(memtuples, t_last, sizeof(HeapTuple), - (int (*) (const void *, const void *)) _psort_cmp); - - if (LACKMEM(node)) /* in-memory sort is impossible */ - { - int t; - - Assert(!foundeor); - inittapes(node); - /* put tuples into leftist tree for createrun */ - for (t = t_last - 1; t >= 0; t--) - puttuple(&PS(node)->Tuples, memtuples[t], 0, &PS(node)->treeContext); - pfree(memtuples); - foundeor = ! createrun(node, PS(node)->Tape->tp_tapenum); - } - else - { - Assert(foundeor); - PS(node)->memtuples = memtuples; - } - - return !foundeor; -} - -/* - * createrun - * - * Create the next run and write it to desttapenum, grabbing the tuples by - * executing the subplan passed in - * - * Uses: - * Tuples, which should contain any tuples for this run - * - * Returns: - * FALSE iff process through end of relation - * Tuples contains the tuples for the following run upon exit - */ -static bool -createrun(Sort *node, int desttapenum) -{ - HeapTuple lasttuple; - HeapTuple tup; - TupleTableSlot *cr_slot; - HeapTuple *memtuples; - int t_last = -1; - int t_free = 1000; - bool foundeor = false; - short junk; - - Assert(node != (Sort *) NULL); - Assert(PS(node) != (Psortstate *) NULL); - Assert(PS(node)->using_tape_files); - - lasttuple = NULL; - memtuples = palloc(t_free * sizeof(HeapTuple)); - - for (;;) - { - while (LACKMEM(node) && PS(node)->Tuples != NULL) - { - if (lasttuple != NULL) - { - FREEMEM(node, lasttuple->t_len); - FREE(lasttuple); - TRACEMEM(createrun); - } - lasttuple = gettuple(&PS(node)->Tuples, &junk, - &PS(node)->treeContext); - PUTTUP(node, lasttuple, desttapenum); - TRACEOUT(createrun, lasttuple); - } - - if (LACKMEM(node)) - break; - - /* - * About to call ExecProcNode, it can mess up the state if it - * eventually calls another Sort node. So must stow it away here - * for the meantime. -Rex - * 2.2.1995 - */ - - cr_slot = ExecProcNode(outerPlan((Plan *) node), (Plan *) node); - - if (TupIsNull(cr_slot)) - { - foundeor = true; - break; - } - else - { - tup = heap_copytuple(cr_slot->val); - ExecClearTuple(cr_slot); - PS(node)->tupcount++; - } - - IncrProcessed(); - USEMEM(node, tup->t_len); - TRACEMEM(createrun); - if (lasttuple != NULL && tuplecmp(tup, lasttuple, - &PS(node)->treeContext)) - { - if (t_free <= 0) - { - t_free = 1000; - memtuples = repalloc(memtuples, - (t_last + t_free + 1) * sizeof(HeapTuple)); - } - t_last++; - t_free--; - memtuples[t_last] = tup; - } - else - puttuple(&PS(node)->Tuples, tup, 0, &PS(node)->treeContext); - } - if (lasttuple != NULL) - { - FREEMEM(node, lasttuple->t_len); - FREE(lasttuple); - TRACEMEM(createrun); - } - dumptuples(node, desttapenum); - ENDRUN(node, desttapenum); /* delimit the end of the run */ - - t_last++; - /* put tuples for the next run into leftist tree */ - if (t_last >= 1) - { - int t; - - PsortTupDesc = PS(node)->treeContext.tupDesc; - PsortKeys = PS(node)->treeContext.scanKeys; - PsortNkeys = PS(node)->treeContext.nKeys; - qsort(memtuples, t_last, sizeof(HeapTuple), - (int (*) (const void *, const void *)) _psort_cmp); - for (t = t_last - 1; t >= 0; t--) - puttuple(&PS(node)->Tuples, memtuples[t], 0, &PS(node)->treeContext); - } - - pfree(memtuples); - - return !foundeor; -} - -/* - * mergeruns - merges all runs from input tapes - * (polyphase merge Alg.D(D6)--Knuth, Vol.3, p271) - * - * Returns: - * tape number of finished tape containing all tuples in order - */ -static int -mergeruns(Sort *node) -{ - struct tape *tp; - - Assert(node != (Sort *) NULL); - Assert(PS(node) != (Psortstate *) NULL); - Assert(PS(node)->using_tape_files); - - tp = PS(node)->Tape + PS(node)->TapeRange; - merge(node, tp); - while (--PS(node)->Level != 0) - { - /* rewind output tape to use as new input */ - LogicalTapeRewind(PS(node)->tapeset, tp->tp_tapenum, false); - tp = tp->tp_prev; - /* rewind new output tape and prepare it for write pass */ - LogicalTapeRewind(PS(node)->tapeset, tp->tp_tapenum, true); - merge(node, tp); - } - /* freeze and rewind the final output tape */ - LogicalTapeFreeze(PS(node)->tapeset, tp->tp_tapenum); - return tp->tp_tapenum; -} - -/* - * merge - handles a single merge of the tape - * (polyphase merge Alg.D(D5)--Knuth, Vol.3, p271) - */ -static void -merge(Sort *node, struct tape * dest) -{ - HeapTuple tup; - struct tape *lasttp; /* (TAPE[P]) */ - struct tape *tp; - struct leftist *tuples; - int desttapenum; - int times; /* runs left to merge */ - int outdummy; /* complete dummy runs */ - short fromtape; - unsigned int tuplen; - - Assert(node != (Sort *) NULL); - Assert(PS(node) != (Psortstate *) NULL); - Assert(PS(node)->using_tape_files); - - lasttp = dest->tp_prev; - times = lasttp->tp_fib; - for (tp = lasttp; tp != dest; tp = tp->tp_prev) - tp->tp_fib -= times; - tp->tp_fib += times; - /* Tape[].tp_fib (A[]) is set to proper exit values */ - - if (PS(node)->TotalDummy < PS(node)->TapeRange) /* no complete dummy - * runs */ - outdummy = 0; - else - { - outdummy = PS(node)->TotalDummy; /* a large positive number */ - for (tp = lasttp; tp != dest; tp = tp->tp_prev) - if (outdummy > tp->tp_dummy) - outdummy = tp->tp_dummy; - for (tp = lasttp; tp != dest; tp = tp->tp_prev) - tp->tp_dummy -= outdummy; - tp->tp_dummy += outdummy; - PS(node)->TotalDummy -= outdummy * PS(node)->TapeRange; - /* do not add the outdummy runs yet */ - times -= outdummy; - } - desttapenum = dest->tp_tapenum; - while (times-- != 0) - { /* merge one run */ - tuples = NULL; - if (PS(node)->TotalDummy == 0) - for (tp = dest->tp_prev; tp != dest; tp = tp->tp_prev) - { - GETLEN(node, tuplen, tp->tp_tapenum); - tup = ALLOCTUP(tuplen); - USEMEM(node, tuplen); - TRACEMEM(merge); - GETTUP(node, tup, tuplen, tp->tp_tapenum); - puttuple(&tuples, tup, tp - PS(node)->Tape, - &PS(node)->treeContext); - } - else - { - for (tp = dest->tp_prev; tp != dest; tp = tp->tp_prev) - { - if (tp->tp_dummy != 0) - { - tp->tp_dummy--; - PS(node)->TotalDummy--; - } - else - { - GETLEN(node, tuplen, tp->tp_tapenum); - tup = ALLOCTUP(tuplen); - USEMEM(node, tuplen); - TRACEMEM(merge); - GETTUP(node, tup, tuplen, tp->tp_tapenum); - puttuple(&tuples, tup, tp - PS(node)->Tape, - &PS(node)->treeContext); - } - } - } - while (tuples != NULL) - { - /* possible optimization by using count in tuples */ - tup = gettuple(&tuples, &fromtape, &PS(node)->treeContext); - PUTTUP(node, tup, desttapenum); - FREEMEM(node, tup->t_len); - FREE(tup); - TRACEMEM(merge); - if (TRYGETLEN(node, tuplen, PS(node)->Tape[fromtape].tp_tapenum)) - { - tup = ALLOCTUP(tuplen); - USEMEM(node, tuplen); - TRACEMEM(merge); - GETTUP(node, tup, tuplen, PS(node)->Tape[fromtape].tp_tapenum); - puttuple(&tuples, tup, fromtape, &PS(node)->treeContext); - } - } - ENDRUN(node, desttapenum); - } - PS(node)->TotalDummy += outdummy; -} - -/* - * dumptuples - stores all the tuples remaining in tree to dest tape - */ -static void -dumptuples(Sort *node, int desttapenum) -{ - LeftistContext context = &PS(node)->treeContext; - struct leftist **treep = &PS(node)->Tuples; - struct leftist *tp; - struct leftist *newp; - HeapTuple tup; - - Assert(PS(node)->using_tape_files); - - tp = *treep; - while (tp != NULL) - { - tup = tp->lt_tuple; - if (tp->lt_dist == 1) /* lt_right == NULL */ - newp = tp->lt_left; - else - newp = lmerge(tp->lt_left, tp->lt_right, context); - pfree(tp); - PUTTUP(node, tup, desttapenum); - FREEMEM(node, tup->t_len); - FREE(tup); - - tp = newp; - } - *treep = NULL; -} - -/* - * psort_grabtuple - gets a tuple from the sorted file and returns it. - * If there are no tuples left, returns NULL. - * Should not call psort_end unless this has returned - * a NULL indicating the last tuple has been processed. - */ -HeapTuple -psort_grabtuple(Sort *node, bool *should_free) -{ - HeapTuple tup; - - Assert(node != (Sort *) NULL); - Assert(PS(node) != (Psortstate *) NULL); - - if (PS(node)->using_tape_files == true) - { - unsigned int tuplen; - - *should_free = true; - if (ScanDirectionIsForward(node->plan.state->es_direction)) - { - if (PS(node)->all_fetched) - return NULL; - if (TRYGETLEN(node, tuplen, PS(node)->psort_grab_tape)) - { - tup = ALLOCTUP(tuplen); - GETTUP(node, tup, tuplen, PS(node)->psort_grab_tape); - return tup; - } - else - { - PS(node)->all_fetched = true; - return NULL; - } - } - /* Backward. - * - * if all tuples are fetched already then we return last tuple, - * else - tuple before last returned. - */ - if (PS(node)->all_fetched) - { - /* - * Assume seek position is pointing just past the zero tuplen - * at the end of file; back up and fetch last tuple's ending - * length word. If seek fails we must have a completely empty - * file. - */ - if (! LogicalTapeBackspace(PS(node)->tapeset, - PS(node)->psort_grab_tape, - 2 * sizeof(tlendummy))) - return NULL; - GETLEN(node, tuplen, PS(node)->psort_grab_tape); - PS(node)->all_fetched = false; - } - else - { - /* - * Back up and fetch prev tuple's ending length word. - * If seek fails, assume we are at start of file. - */ - if (! LogicalTapeBackspace(PS(node)->tapeset, - PS(node)->psort_grab_tape, - sizeof(tlendummy))) - return NULL; - GETLEN(node, tuplen, PS(node)->psort_grab_tape); - /* - * Back up to get ending length word of tuple before it. - */ - if (! LogicalTapeBackspace(PS(node)->tapeset, - PS(node)->psort_grab_tape, - tuplen + 2*sizeof(tlendummy))) - { - /* If fail, presumably the prev tuple is the first in the file. - * Back up so that it becomes next to read in forward direction - * (not obviously right, but that is what in-memory case does) - */ - if (! LogicalTapeBackspace(PS(node)->tapeset, - PS(node)->psort_grab_tape, - tuplen + sizeof(tlendummy))) - elog(ERROR, "psort_grabtuple: too big last tuple len in backward scan"); - return NULL; - } - GETLEN(node, tuplen, PS(node)->psort_grab_tape); - } - - /* - * Now we have the length of the prior tuple, back up and read it. - * Note: GETTUP expects we are positioned after the initial length - * word of the tuple, so back up to that point. - */ - if (! LogicalTapeBackspace(PS(node)->tapeset, - PS(node)->psort_grab_tape, - tuplen)) - elog(ERROR, "psort_grabtuple: too big tuple len in backward scan"); - tup = ALLOCTUP(tuplen); - GETTUP(node, tup, tuplen, PS(node)->psort_grab_tape); - return tup; - } - else - { - *should_free = false; - if (ScanDirectionIsForward(node->plan.state->es_direction)) - { - if (PS(node)->psort_current < PS(node)->tupcount) - return PS(node)->memtuples[PS(node)->psort_current++]; - else - { - PS(node)->all_fetched = true; - return NULL; - } - } - /* Backward */ - if (PS(node)->psort_current <= 0) - return NULL; - - /* - * if all tuples are fetched already then we return last tuple, - * else - tuple before last returned. - */ - if (PS(node)->all_fetched) - PS(node)->all_fetched = false; - else - { - PS(node)->psort_current--; /* last returned tuple */ - if (PS(node)->psort_current <= 0) - return NULL; - } - return PS(node)->memtuples[PS(node)->psort_current - 1]; - } -} - -/* - * psort_markpos - saves current position in the merged sort file - * - * XXX I suspect these need to save & restore the all_fetched flag as well! - */ -void -psort_markpos(Sort *node) -{ - Assert(node != (Sort *) NULL); - Assert(PS(node) != (Psortstate *) NULL); - - if (PS(node)->using_tape_files == true) - LogicalTapeTell(PS(node)->tapeset, - PS(node)->psort_grab_tape, - & PS(node)->psort_saved, - & PS(node)->psort_saved_offset); - else - PS(node)->psort_saved = PS(node)->psort_current; -} - -/* - * psort_restorepos- restores current position in merged sort file to - * last saved position - */ -void -psort_restorepos(Sort *node) -{ - Assert(node != (Sort *) NULL); - Assert(PS(node) != (Psortstate *) NULL); - - if (PS(node)->using_tape_files == true) - { - if (! LogicalTapeSeek(PS(node)->tapeset, - PS(node)->psort_grab_tape, - PS(node)->psort_saved, - PS(node)->psort_saved_offset)) - elog(ERROR, "psort_restorepos failed"); - } - else - PS(node)->psort_current = PS(node)->psort_saved; -} - -/* - * psort_end - * - * Release resources and clean up. - */ -void -psort_end(Sort *node) -{ - /* node->cleaned is probably redundant? */ - if (!node->cleaned && PS(node) != (Psortstate *) NULL) - { - if (PS(node)->tapeset) - LogicalTapeSetClose(PS(node)->tapeset); - if (PS(node)->memtuples) - pfree(PS(node)->memtuples); - - /* XXX what about freeing leftist tree and tuples in memory? */ - - NDirectFileRead += (int) ceil((double) PS(node)->BytesRead / BLCKSZ); - NDirectFileWrite += (int) ceil((double) PS(node)->BytesWritten / BLCKSZ); - - pfree((void *) node->psortstate); - node->psortstate = NULL; - node->cleaned = TRUE; - } -} - -void -psort_rescan(Sort *node) -{ - - /* - * If subnode is to be rescanned then free our previous results - */ - if (((Plan *) node)->lefttree->chgParam != NULL) - { - psort_end(node); - node->cleaned = false; /* huh? */ - } - else if (PS(node) != (Psortstate *) NULL) - { - PS(node)->all_fetched = false; - PS(node)->psort_current = 0; - PS(node)->psort_saved = 0L; - PS(node)->psort_saved_offset = 0; - if (PS(node)->using_tape_files == true) - LogicalTapeRewind(PS(node)->tapeset, - PS(node)->psort_grab_tape, - false); - } - -} - -static int -_psort_cmp(HeapTuple *ltup, HeapTuple *rtup) -{ - Datum lattr, - rattr; - int nkey; - int result = 0; - bool isnull1, - isnull2; - - for (nkey = 0; nkey < PsortNkeys && !result; nkey++) - { - lattr = heap_getattr(*ltup, - PsortKeys[nkey].sk_attno, - PsortTupDesc, - &isnull1); - rattr = heap_getattr(*rtup, - PsortKeys[nkey].sk_attno, - PsortTupDesc, - &isnull2); - if (isnull1) - { - if (!isnull2) - result = 1; - } - else if (isnull2) - result = -1; - - else if (PsortKeys[nkey].sk_flags & SK_COMMUTE) - { - if (!(result = -(long) (*fmgr_faddr(&PsortKeys[nkey].sk_func)) (rattr, lattr))) - result = (long) (*fmgr_faddr(&PsortKeys[nkey].sk_func)) (lattr, rattr); - } - else if (!(result = -(long) (*fmgr_faddr(&PsortKeys[nkey].sk_func)) (lattr, rattr))) - result = (long) (*fmgr_faddr(&PsortKeys[nkey].sk_func)) (rattr, lattr); - } - return result; -} diff --git a/src/include/lib/qsort.h b/src/include/lib/qsort.h deleted file mode 100644 index d7bd348f86..0000000000 --- a/src/include/lib/qsort.h +++ /dev/null @@ -1,22 +0,0 @@ -/*------------------------------------------------------------------------- - * - * qsort.h - * - * - * - * Copyright (c) 1994, Regents of the University of California - * - * $Id: qsort.h,v 1.7 1999/02/13 23:21:32 momjian Exp $ - * - *------------------------------------------------------------------------- - */ -#ifndef QSORT_H -#define QSORT_H - - -extern void pg_qsort(void *bot, - size_t nmemb, - size_t size, - int (*compar) (void *, void *)); - -#endif /* QSORT_H */ diff --git a/src/include/utils/lselect.h b/src/include/utils/lselect.h deleted file mode 100644 index 4598c2ab86..0000000000 --- a/src/include/utils/lselect.h +++ /dev/null @@ -1,51 +0,0 @@ -/*------------------------------------------------------------------------- - * - * lselect.h - * definitions for the replacement selection algorithm. - * - * - * Copyright (c) 1994, Regents of the University of California - * - * $Id: lselect.h,v 1.14 1999/07/17 20:18:36 momjian Exp $ - * - *------------------------------------------------------------------------- - */ -#ifndef LSELECT_H -#define LSELECT_H - -#include "utils/syscache.h" - -struct leftist -{ - short lt_dist; /* distance to leaf/empty node */ - short lt_devnum; /* device number of tuple */ - HeapTuple lt_tuple; - struct leftist *lt_left; - struct leftist *lt_right; -}; - -/* replaces global variables in lselect.c to make it reentrant */ -typedef struct -{ - TupleDesc tupDesc; - int nKeys; - ScanKey scanKeys; - int sortMem; /* needed for psort */ -} LeftistContextData; -typedef LeftistContextData *LeftistContext; - -extern struct leftist *lmerge(struct leftist * pt, struct leftist * qt, - LeftistContext context); -extern HeapTuple gettuple(struct leftist ** treep, short *devnum, - LeftistContext context); -extern void puttuple(struct leftist ** treep, HeapTuple newtuple, short devnum, - LeftistContext context); -extern int tuplecmp(HeapTuple ltup, HeapTuple rtup, LeftistContext context); - -#ifdef EBUG -extern void checktree(struct leftist * tree, LeftistContext context); -extern int checktreer(struct leftist * tree, int level, LeftistContext context); - -#endif /* EBUG */ - -#endif /* LSELECT_H */ diff --git a/src/include/utils/psort.h b/src/include/utils/psort.h deleted file mode 100644 index 5f7a638442..0000000000 --- a/src/include/utils/psort.h +++ /dev/null @@ -1,26 +0,0 @@ -/*------------------------------------------------------------------------- - * - * psort.h - * Polyphase merge sort. - * - * Copyright (c) 1994, Regents of the University of California - * - * $Id: psort.h,v 1.23 1999/10/16 19:49:28 tgl Exp $ - * - *------------------------------------------------------------------------- - */ -#ifndef PSORT_H -#define PSORT_H - -#include "access/htup.h" -#include "access/skey.h" -#include "nodes/plannodes.h" - -extern bool psort_begin(Sort *node, int nkeys, ScanKey key); -extern HeapTuple psort_grabtuple(Sort *node, bool *should_free); -extern void psort_markpos(Sort *node); -extern void psort_restorepos(Sort *node); -extern void psort_end(Sort *node); -extern void psort_rescan(Sort *node); - -#endif /* PSORT_H */