blob: 01e449e062b1b46927d1feae341a51d0506d8c5c [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*-------------------------------------------------------------------------
*
* cdbheaptest.c
*
*/
#include "postgres.h"
#include <assert.h>
#include <ctype.h>
#include "fmgr.h"
#include "cdb/cdbheap.h"
#include "cdbheaptest.h"
typedef struct
{
int *value;
int source;
}HeapValue;
static int cmpIntP(void *lhs, void *rhs);
static void *createIntP(void *nothing, void *data);
static void copyIntP(void *dst, void *src);
static void switchIntP(void *left, void *right);
static int cmpint( const void *lhs, const void *rhs );
static int GetNextValueForSlot( HeapValue *values, int slot, int startIndex, int stopIndex );
int cmpIntP(void *lhs, void *rhs)
{
HeapValue *l;
HeapValue *r;
int cmp;
Assert( lhs != NULL && rhs != NULL );
l = (HeapValue *)lhs;
r = (HeapValue *)rhs;
if ( l->value == NULL )
{
if ( r->value == NULL )
return 0;
return 1;
}
if ( r->value == NULL )
return -1;
cmp = *(l->value) - *(r->value);
if ( cmp < 0 )
return -1;
else if ( cmp == 0 )
return 0;
else
return 1;
}
void *createIntP(void *nothing, void *data)
{
HeapValue *p;
HeapValue *heapdata;
Assert( data != NULL );
heapdata = (HeapValue *)data;
p = palloc0(sizeof(HeapValue));
p->value = heapdata->value;
p->source = heapdata->source;
return (void *)p;
}
void copyIntP(void *dst, void *src)
{
HeapValue *l;
HeapValue *r;
Assert( dst != NULL && src != NULL );
l = (HeapValue *)dst;
r = (HeapValue *)src;
l->value = r->value;
l->source = r->source;
}
void switchIntP(void *left, void *right)
{
HeapValue *l;
HeapValue *r;
int* ptmp;
int tmp;
Assert( left != NULL && right != NULL );
l = (HeapValue *)left;
r = (HeapValue *)right;
ptmp = l->value;
l->value = r->value;
r->value = ptmp;
tmp = l->source;
l->source = r->source;
r->source = tmp;
}
int cmpint( const void *lhs, const void *rhs )
{
return ((*(int *)lhs) - (*(int *)rhs));
}
/*
* cdb_heap_test takes 2 arguments:
* 1) the number of elements in the heap
* 2) the total number of integers to randomly generate
*/
PG_FUNCTION_INFO_V1(cdb_heap_test);
Datum
cdb_heap_test(PG_FUNCTION_ARGS)
{
int nSlots = PG_GETARG_INT32(0);
int nToGenerate = PG_GETARG_INT32(1);
int seed = PG_GETARG_INT32(2);
bool result = true;
CdbHeap *cdbheap = NULL;
int i;
int *intvals;
HeapValue* values;
int *slotcounts;
int *slotpositions;
HeapValue *phv;
Assert(nSlots >= 1 && nToGenerate >= 1 );
cdbheap = CreateCdbHeap( nSlots,
cmpIntP,
createIntP,
copyIntP,
switchIntP,
NULL);
/*
* Generate nToGenerate random integers
*/
intvals = (int *)palloc0( nToGenerate * sizeof(int) );
srand( seed );
for ( i=0; i<nToGenerate; i++ )
{
intvals[i] = rand();
}
// Now sort these
qsort( intvals, nToGenerate, sizeof(int), cmpint );
// Now allocate nSlots arrays for the sorted ints, and an array for the counts
values = (HeapValue *)palloc0( nToGenerate * sizeof(HeapValue));
slotcounts = (int *)palloc0( nSlots * sizeof(int) );
slotpositions = (int *)palloc0( nSlots * sizeof(int) );
// Now randomly assign the values to nSlots, preserving order
for ( i=0; i<nToGenerate; i++ )
{
int slot = floor( ((double)rand() / ((double)RAND_MAX + 1 )) * nSlots);
Assert( slot >= 0 && slot < nSlots);
values[i].source = slot;
values[i].value = intvals + i;
slotcounts[slot]++;
}
elog( DEBUG4, "Slot counts follow" );
int sum = 0;
for ( i=0; i<nSlots; i++ )
{
if ( slotcounts[i] == 0 )
{
ereport(NOTICE,
(errcode(ERRCODE_MOST_SPECIFIC_TYPE_MISMATCH),
errmsg("Function cdb_heap_test() cannot proceed, because not all slots got values."))
);
result = false;
goto end;
}
sum += slotcounts[i];
elog( DEBUG4, "slotcount[%d] = %d" , i, slotcounts[i]);
}
elog( DEBUG4, "slotcount total = %d" , sum);
// Now add the first element from each slot to the heap.
for ( i=0; i<nSlots; i++ )
{
int index = GetNextValueForSlot( values, i, slotpositions[i], nToGenerate );
SetCdbHeapInitialValue( cdbheap, &values[index] );
slotpositions[i] = index+1;
}
// Now grab lowest element from heap, and ask for the next element from the
// same slot
int lastval = INT_MIN;
int lastslot;
for ( i=0; i<nToGenerate; i++ )
{
HeapValue *phv = (HeapValue *)GetLowestValueFromCdbHeap( cdbheap );
Assert( phv != NULL );
if ( phv->value == NULL )
{
ereport(NOTICE,
(errcode(ERRCODE_MOST_SPECIFIC_TYPE_MISMATCH),
errmsg("Function cdb_heap_test() failed. At index %d, value was NULL",
i ))
);
result = false;
goto end;
}
if ( lastval > *phv->value )
{
ereport(NOTICE,
(errcode(ERRCODE_MOST_SPECIFIC_TYPE_MISMATCH),
errmsg("Function cdb_heap_test() failed. At index %d, value %d was smaller than previous value %d",
i, *phv->value, lastval ))
);
result = false;
goto end;
}
lastval = *phv->value;
lastslot = phv->source;
int index = GetNextValueForSlot( values, lastslot, slotpositions[lastslot], nToGenerate );
if ( index == -1 )
phv->value = NULL;
else
{
phv = &values[index];
slotpositions[lastslot] = index + 1;
}
MergeNewValueIntoCdbHeap( cdbheap, phv );
}
phv = GetLowestValueFromCdbHeap( cdbheap );
Assert( phv != NULL && phv->value == NULL );
end:
if ( cdbheap != NULL )
DestroyCdbHeap( cdbheap );
PG_RETURN_BOOL(result);
}
int GetNextValueForSlot( HeapValue *values, int slot, int startIndex, int stopIndex )
{
int i;
for ( i=startIndex; i<stopIndex; i++ )
{
if ( values[i].source == slot )
{
return i;
}
}
return -1;
}