8
8
* Portions Copyright (c) 1994, Regents of the University of California
9
9
*
10
10
* IDENTIFICATION
11
- * $PostgreSQL: pgsql/src/backend/access/gin/ginbulk.c,v 1.1 2006/05/02 11:28:54 teodor Exp $
11
+ * $PostgreSQL: pgsql/src/backend/access/gin/ginbulk.c,v 1.2 2006/07/11 16:55:34 teodor Exp $
12
12
*-------------------------------------------------------------------------
13
13
*/
14
14
22
22
#include "utils/memutils.h"
23
23
#include "access/tuptoaster.h"
24
24
25
- #define DEF_NENTRY 128
25
+ #define DEF_NENTRY 2048
26
26
#define DEF_NPTR 4
27
27
28
28
void
29
29
ginInitBA (BuildAccumulator * accum ) {
30
-
31
- accum -> number = 0 ;
32
- accum -> curget = 0 ;
33
- accum -> length = DEF_NENTRY ;
34
- accum -> entries = (EntryAccumulator * )palloc0 ( sizeof (EntryAccumulator ) * DEF_NENTRY );
35
- accum -> allocatedMemory = sizeof (EntryAccumulator ) * DEF_NENTRY ;
30
+ accum -> maxdepth = 1 ;
31
+ accum -> stackpos = 0 ;
32
+ accum -> entries = NULL ;
33
+ accum -> stack = NULL ;
34
+ accum -> allocatedMemory = 0 ;
35
+ accum -> entryallocator = NULL ;
36
+ }
37
+
38
+ static EntryAccumulator *
39
+ EAAllocate ( BuildAccumulator * accum ) {
40
+ if ( accum -> entryallocator == NULL || accum -> length >=DEF_NENTRY ) {
41
+ accum -> entryallocator = palloc (sizeof (EntryAccumulator )* DEF_NENTRY );
42
+ accum -> allocatedMemory += sizeof (EntryAccumulator )* DEF_NENTRY ;
43
+ accum -> length = 0 ;
44
+ }
45
+
46
+ accum -> length ++ ;
47
+ return accum -> entryallocator + accum -> length - 1 ;
36
48
}
37
49
38
50
/*
@@ -61,64 +73,133 @@ ginInsertData(BuildAccumulator *accum, EntryAccumulator *entry, ItemPointer heap
61
73
entry -> number ++ ;
62
74
}
63
75
76
+ static Datum
77
+ getDatumCopy (BuildAccumulator * accum , Datum value ) {
78
+ Form_pg_attribute * att = accum -> ginstate -> tupdesc -> attrs ;
79
+ Datum newvalue ;
80
+ int data_length = 0 ;
81
+ void * ptr ;
82
+
83
+ if ( att [0 ]-> attbyval ) {
84
+ store_att_byval (& newvalue , value , att [0 ]-> attlen );
85
+ } else {
86
+ /* pass-by-reference */
87
+ if (att [0 ]-> attlen == -1 ) {
88
+ /* varlena */
89
+ data_length = VARATT_SIZE (DatumGetPointer (value ));
90
+ } else if (att [0 ]-> attlen == -2 ) {
91
+ /* c-string */
92
+ data_length = strlen (DatumGetCString (value )) + 1 ;
93
+ } else {
94
+ /* fixed-length pass-by-reference */
95
+ Assert (att [0 ]-> attlen > 0 );
96
+ data_length = att [0 ]-> attlen ;
97
+ }
98
+
99
+ ptr = palloc ( data_length );
100
+ memcpy (ptr , DatumGetPointer (value ), data_length );
101
+ newvalue = PointerGetDatum (ptr );
102
+ }
103
+
104
+ accum -> allocatedMemory += data_length ;
105
+
106
+ return newvalue ;
107
+ }
108
+
64
109
/*
65
110
* Find/store one entry from indexed value.
66
- * It supposes, that entry should be located between low and end of array of
67
- * entries. Returns position of found/inserted entry
68
111
*/
69
- static uint32
70
- ginInsertEntry (BuildAccumulator * accum , ItemPointer heapptr , Datum entry , uint32 low ) {
71
- uint32 high = accum -> number , mid ;
72
- int res ;
73
-
74
- while (high > low ) {
75
- mid = low + ((high - low ) / 2 );
76
-
77
- res = compareEntries (accum -> ginstate , entry , accum -> entries [mid ].value );
78
-
79
- if ( res == 0 ) {
80
- ginInsertData ( accum , accum -> entries + mid , heapptr );
81
- return mid ;
82
- } else if ( res > 0 )
83
- low = mid + 1 ;
84
- else
85
- high = mid ;
112
+ static void
113
+ ginInsertEntry (BuildAccumulator * accum , ItemPointer heapptr , Datum entry ) {
114
+ EntryAccumulator * ea = accum -> entries , * pea = NULL ;
115
+ int res = 0 ;
116
+ uint32 depth = 1 ;
117
+
118
+ while ( ea ) {
119
+ res = compareEntries (accum -> ginstate , entry , ea -> value );
120
+ if ( res == 0 )
121
+ break ; /* found */
122
+ else {
123
+ pea = ea ;
124
+ if ( res < 0 )
125
+ ea = ea -> left ;
126
+ else
127
+ ea = ea -> right ;
128
+ }
129
+ depth ++ ;
86
130
}
87
131
88
- /* did not find an entry, insert */
89
- if ( accum -> number >= accum -> length ) {
90
- accum -> allocatedMemory += sizeof (EntryAccumulator ) * accum -> length ;
91
- accum -> length *= 2 ;
92
- accum -> entries = (EntryAccumulator * )repalloc ( accum -> entries ,
93
- sizeof (EntryAccumulator ) * accum -> length );
94
- }
95
-
96
- if ( high != accum -> number )
97
- memmove ( accum -> entries + high + 1 , accum -> entries + high , sizeof (EntryAccumulator ) * (accum -> number - high ) );
132
+ if ( depth > accum -> maxdepth )
133
+ accum -> maxdepth = depth ;
98
134
99
- accum -> entries [high ].value = entry ;
100
- accum -> entries [high ].length = DEF_NPTR ;
101
- accum -> entries [high ].number = 1 ;
102
- accum -> entries [high ].shouldSort = FALSE;
103
- accum -> entries [high ].list = (ItemPointerData * )palloc (sizeof (ItemPointerData )* DEF_NPTR );
104
- accum -> entries [high ].list [0 ] = * heapptr ;
135
+ if ( ea == NULL ) {
136
+ ea = EAAllocate (accum );
105
137
106
- accum -> allocatedMemory += sizeof (ItemPointerData )* DEF_NPTR ;
107
- accum -> number ++ ;
138
+ ea -> left = ea -> right = NULL ;
139
+ ea -> value = getDatumCopy (accum , entry );
140
+ ea -> length = DEF_NPTR ;
141
+ ea -> number = 1 ;
142
+ ea -> shouldSort = FALSE;
143
+ ea -> list = (ItemPointerData * )palloc (sizeof (ItemPointerData )* DEF_NPTR );
144
+ ea -> list [0 ] = * heapptr ;
145
+ accum -> allocatedMemory += sizeof (ItemPointerData )* DEF_NPTR ;
108
146
109
- return high ;
147
+ if ( pea == NULL )
148
+ accum -> entries = ea ;
149
+ else {
150
+ Assert ( res != 0 );
151
+ if ( res < 0 )
152
+ pea -> left = ea ;
153
+ else
154
+ pea -> right = ea ;
155
+ }
156
+ } else
157
+ ginInsertData ( accum , ea , heapptr );
110
158
}
111
159
160
+ /*
161
+ * insert middle of left part the middle of right one,
162
+ * then calls itself for each parts
163
+ */
164
+ static void
165
+ ginChooseElem (BuildAccumulator * accum , ItemPointer heapptr , Datum * entries , uint32 nentry ,
166
+ uint32 low , uint32 high , uint32 offset ) {
167
+ uint32 pos ;
168
+ uint32 middle = (low + high )>>1 ;
169
+
170
+ pos = (low + middle )>>1 ;
171
+ if ( low != middle && pos >=offset && pos - offset < nentry )
172
+ ginInsertEntry ( accum , heapptr , entries [ pos - offset ]);
173
+ pos = (high + middle + 1 )>>1 ;
174
+ if ( middle + 1 != high && pos >=offset && pos - offset < nentry )
175
+ ginInsertEntry ( accum , heapptr , entries [ pos - offset ]);
176
+
177
+ if ( low != middle )
178
+ ginChooseElem (accum , heapptr , entries , nentry , low , middle , offset );
179
+ if ( high != middle + 1 )
180
+ ginChooseElem (accum , heapptr , entries , nentry , middle + 1 , high , offset );
181
+ }
112
182
113
183
/*
114
- * Insert one heap pointer. Requires entries to be sorted!
184
+ * Insert one heap pointer. Suppose entries is sorted.
185
+ * Insertion order trys to get binary tree balanced: first insert middle value,
186
+ * next middle on left part and middle of right part.
115
187
*/
116
188
void
117
189
ginInsertRecordBA ( BuildAccumulator * accum , ItemPointer heapptr , Datum * entries , uint32 nentry ) {
118
- uint32 start = 0 ,i ;
190
+ uint32 i , nbit = 0 , offset ;
191
+
192
+ if (nentry == 0 )
193
+ return ;
194
+
195
+ i = nentry - 1 ;
196
+ for (;i > 0 ;i >>=1 ) nbit ++ ;
119
197
120
- for (i = 0 ;i < nentry ;i ++ )
121
- start = ginInsertEntry ( accum , heapptr , entries [i ], start );
198
+ nbit = 1 <<nbit ;
199
+ offset = (nbit - nentry )/2 ;
200
+
201
+ ginInsertEntry ( accum , heapptr , entries [ (nbit >>1 )- offset ]);
202
+ ginChooseElem (accum , heapptr , entries , nentry , 0 , nbit , offset );
122
203
}
123
204
124
205
static int
@@ -128,28 +209,79 @@ qsortCompareItemPointers( const void *a, const void *b ) {
128
209
return res ;
129
210
}
130
211
212
+ /*
213
+ * walk on binary tree and returns ordered nodes
214
+ */
215
+ static EntryAccumulator *
216
+ walkTree ( BuildAccumulator * accum ) {
217
+ EntryAccumulator * entry = accum -> stack [ accum -> stackpos ];
218
+
219
+ if ( entry -> list != NULL ) {
220
+ /* return entry itself: we already was at left sublink */
221
+ return entry ;
222
+ } else if ( entry -> right && entry -> right != accum -> stack [ accum -> stackpos + 1 ] ) {
223
+ /* go on right sublink */
224
+ accum -> stackpos ++ ;
225
+ entry = entry -> right ;
226
+
227
+ /* find most-left value */
228
+ for (;;) {
229
+ accum -> stack [ accum -> stackpos ] = entry ;
230
+ if ( entry -> left ) {
231
+ accum -> stackpos ++ ;
232
+ entry = entry -> left ;
233
+ } else
234
+ break ;
235
+ }
236
+ } else {
237
+ /* we already return all left subtree, itself and right subtree */
238
+ if ( accum -> stackpos == 0 )
239
+ return 0 ;
240
+ accum -> stackpos -- ;
241
+ return walkTree (accum );
242
+ }
243
+
244
+ return entry ;
245
+ }
246
+
131
247
ItemPointerData *
132
248
ginGetEntry (BuildAccumulator * accum , Datum * value , uint32 * n ) {
133
249
EntryAccumulator * entry ;
134
-
135
250
ItemPointerData * list ;
136
- if ( accum -> curget >= accum -> number )
251
+
252
+
253
+ if ( accum -> stack == NULL ) {
254
+ /* first call */
255
+ accum -> stack = palloc0 (sizeof (EntryAccumulator * )* (accum -> maxdepth + 1 ));
256
+ entry = accum -> entries ;
257
+
258
+ /* find most-left value */
259
+ for (;;) {
260
+ accum -> stack [ accum -> stackpos ] = entry ;
261
+ if ( entry -> left ) {
262
+ accum -> stackpos ++ ;
263
+ entry = entry -> left ;
264
+ } else
265
+ break ;
266
+ }
267
+ } else {
268
+ pfree ( accum -> stack [ accum -> stackpos ]-> list );
269
+ accum -> stack [ accum -> stackpos ]-> list = NULL ;
270
+ entry = walkTree ( accum );
271
+ }
272
+
273
+ if ( entry == NULL )
137
274
return NULL ;
138
- else if ( accum -> curget > 0 )
139
- pfree ( accum -> entries [ accum -> curget - 1 ].list );
140
275
141
- entry = accum -> entries + accum -> curget ;
142
276
* n = entry -> number ;
143
277
* value = entry -> value ;
144
278
list = entry -> list ;
145
- accum -> curget ++ ;
279
+
280
+ Assert (list != NULL );
146
281
147
282
if ( entry -> shouldSort && entry -> number > 1 )
148
283
qsort (list , * n , sizeof (ItemPointerData ), qsortCompareItemPointers );
149
284
150
-
151
285
return list ;
152
286
}
153
287
154
-
155
-
0 commit comments