1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-10 17:42:29 +03:00
Files
postgres/src/backend/utils/sort/lselect.c
Vadim B. Mikheev 712ea2507e 1. Use qsort for first run
2. Limit number of tuples in leftist trees:
	- put one tuple from current tree to disk if limit reached;
	- end run creation if limit reached by nextrun.
3. Avoid mergeruns() if first run is single one!
1997-09-18 05:37:31 +00:00

355 lines
7.5 KiB
C

/*-------------------------------------------------------------------------
*
* 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.9 1997/09/18 05:37:30 vadim Exp $
*
*-------------------------------------------------------------------------
*/
#include <string.h>
#include <stdio.h>
#include "postgres.h"
#include "storage/buf.h"
#include "access/skey.h"
#include "access/heapam.h"
#include "access/htup.h"
#include "utils/rel.h"
#include "utils/psort.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)
{
register 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)
{
register 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)
{
register 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)
{
register struct leftist *new1;
register 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)
{
register Datum lattr,
rattr;
int nkey = 0;
int result = 0;
bool isnull;
if (ltup == (HeapTuple) NULL)
return (0);
if (rtup == (HeapTuple) NULL)
return (1);
while (nkey < context->nKeys && !result)
{
lattr = heap_getattr(ltup, InvalidBuffer,
context->scanKeys[nkey].sk_attno,
context->tupDesc, &isnull);
if (isnull)
return (0);
rattr = heap_getattr(rtup, InvalidBuffer,
context->scanKeys[nkey].sk_attno,
context->tupDesc,
&isnull);
if (isnull)
return (1);
if (context->scanKeys[nkey].sk_flags & SK_COMMUTE)
{
if (!(result =
(long) (*context->scanKeys[nkey].sk_func) (rattr, lattr)))
result =
-(long) (*context->scanKeys[nkey].sk_func) (lattr, rattr);
}
else if (!(result =
(long) (*context->scanKeys[nkey].sk_func) (lattr, rattr)))
result =
-(long) (*context->scanKeys[nkey].sk_func) (rattr, lattr);
nkey++;
}
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