aboutsummaryrefslogtreecommitdiff
path: root/src/backend/access/gin/ginbulk.c
blob: 6d73f070ba26c5eec42e4738ad9cd355814feb24 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/*-------------------------------------------------------------------------
 *
 * ginbulk.c
 *    routines for fast build of inverted index 
 *
 *
 * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * IDENTIFICATION
 *          $PostgreSQL: pgsql/src/backend/access/gin/ginbulk.c,v 1.1 2006/05/02 11:28:54 teodor Exp $
 *-------------------------------------------------------------------------
 */

#include "postgres.h"
#include "access/genam.h"
#include "access/gin.h"
#include "access/heapam.h"
#include "catalog/index.h"
#include "miscadmin.h"
#include "storage/freespace.h"
#include "utils/memutils.h"
#include "access/tuptoaster.h"

#define DEF_NENTRY	128
#define DEF_NPTR	4

void
ginInitBA(BuildAccumulator *accum) {
	
		accum->number = 0;
		accum->curget = 0;
		accum->length = DEF_NENTRY;
		accum->entries = (EntryAccumulator*)palloc0( sizeof(EntryAccumulator) * DEF_NENTRY );
		accum->allocatedMemory = sizeof(EntryAccumulator) * DEF_NENTRY;
}

/*
 * Stores heap item pointer. For robust, it checks that
 * item pointer are ordered
 */
static void
ginInsertData(BuildAccumulator *accum, EntryAccumulator *entry, ItemPointer heapptr) {
	if ( entry->number >= entry->length ) {
		accum->allocatedMemory += sizeof(ItemPointerData) * entry->length;
		entry->length *= 2;
		entry->list    = (ItemPointerData*)repalloc(entry->list,
											sizeof(ItemPointerData)*entry->length);
	}

	if ( entry->shouldSort==FALSE ) {  
		int res = compareItemPointers( entry->list + entry->number - 1, heapptr );

		Assert( res != 0 );

		if ( res > 0 )
			entry->shouldSort=TRUE;
	}

	entry->list[ entry->number ] = *heapptr;
	entry->number++;
}

/*
 * Find/store one entry from indexed value.
 * It supposes, that entry should be located between low and end of array of
 * entries. Returns position of found/inserted entry
 */
static uint32
ginInsertEntry(BuildAccumulator *accum, ItemPointer heapptr,  Datum entry, uint32 low) {
	uint32 high = accum->number, mid;
	int res;

	while(high>low) { 
		mid = low + ((high - low) / 2);

		res = compareEntries(accum->ginstate, entry, accum->entries[mid].value);

		if ( res == 0 ) {
			ginInsertData( accum, accum->entries+mid, heapptr );
			return mid;
		} else if ( res > 0 )
			low = mid + 1;
		else
			high = mid;
	}
	
	/* did not find an entry, insert */
	if ( accum->number >= accum->length ) {
		accum->allocatedMemory += sizeof(EntryAccumulator) * accum->length;
		accum->length *= 2;
		accum->entries = (EntryAccumulator*)repalloc( accum->entries, 
				sizeof(EntryAccumulator) * accum->length );
	}

	if ( high != accum->number ) 
		memmove( accum->entries+high+1, accum->entries+high, sizeof(EntryAccumulator) * (accum->number-high) );

	accum->entries[high].value  = entry;
	accum->entries[high].length = DEF_NPTR;
	accum->entries[high].number = 1;
	accum->entries[high].shouldSort = FALSE;
	accum->entries[high].list   = (ItemPointerData*)palloc(sizeof(ItemPointerData)*DEF_NPTR);
	accum->entries[high].list[0] = *heapptr;

	accum->allocatedMemory += sizeof(ItemPointerData)*DEF_NPTR;
	accum->number++;

	return high;
}


/*
 * Insert one heap pointer. Requires entries to be sorted!
 */
void
ginInsertRecordBA( BuildAccumulator *accum, ItemPointer heapptr, Datum *entries, uint32 nentry ) {
	uint32 start=0,i;

	for(i=0;i<nentry;i++)
		start = ginInsertEntry( accum, heapptr, entries[i], start);
}

static int 
qsortCompareItemPointers( const void *a, const void *b ) {
	int res = compareItemPointers( (ItemPointer)a, (ItemPointer)b );
	Assert( res!=0 );
	return res;
}

ItemPointerData*
ginGetEntry(BuildAccumulator *accum, Datum *value, uint32 *n) {
	EntryAccumulator	*entry;

	ItemPointerData *list;
	if ( accum->curget >= accum->number )
		return NULL;
	else if ( accum->curget > 0 )
		pfree( accum->entries[ accum->curget-1 ].list );

	entry = accum->entries + accum->curget;
	*n 		= entry->number;
	*value 	= entry->value;
	list 	= entry->list;
	accum->curget++;

	if ( entry->shouldSort && entry->number > 1 )
		qsort(list, *n, sizeof(ItemPointerData), qsortCompareItemPointers);


	return list;
}