00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "postgres.h"
00016
00017 #include "access/gin_private.h"
00018 #include "utils/datum.h"
00019 #include "utils/memutils.h"
00020
00021
00022 #define DEF_NENTRY 2048
00023 #define DEF_NPTR 5
00024
00025
00026
00027 static void
00028 ginCombineData(RBNode *existing, const RBNode *newdata, void *arg)
00029 {
00030 GinEntryAccumulator *eo = (GinEntryAccumulator *) existing;
00031 const GinEntryAccumulator *en = (const GinEntryAccumulator *) newdata;
00032 BuildAccumulator *accum = (BuildAccumulator *) arg;
00033
00034
00035
00036
00037 if (eo->count >= eo->maxcount)
00038 {
00039 accum->allocatedMemory -= GetMemoryChunkSpace(eo->list);
00040 eo->maxcount *= 2;
00041 eo->list = (ItemPointerData *)
00042 repalloc(eo->list, sizeof(ItemPointerData) * eo->maxcount);
00043 accum->allocatedMemory += GetMemoryChunkSpace(eo->list);
00044 }
00045
00046
00047 if (eo->shouldSort == FALSE)
00048 {
00049 int res;
00050
00051 res = ginCompareItemPointers(eo->list + eo->count - 1, en->list);
00052 Assert(res != 0);
00053
00054 if (res > 0)
00055 eo->shouldSort = TRUE;
00056 }
00057
00058 eo->list[eo->count] = en->list[0];
00059 eo->count++;
00060 }
00061
00062
00063 static int
00064 cmpEntryAccumulator(const RBNode *a, const RBNode *b, void *arg)
00065 {
00066 const GinEntryAccumulator *ea = (const GinEntryAccumulator *) a;
00067 const GinEntryAccumulator *eb = (const GinEntryAccumulator *) b;
00068 BuildAccumulator *accum = (BuildAccumulator *) arg;
00069
00070 return ginCompareAttEntries(accum->ginstate,
00071 ea->attnum, ea->key, ea->category,
00072 eb->attnum, eb->key, eb->category);
00073 }
00074
00075
00076 static RBNode *
00077 ginAllocEntryAccumulator(void *arg)
00078 {
00079 BuildAccumulator *accum = (BuildAccumulator *) arg;
00080 GinEntryAccumulator *ea;
00081
00082
00083
00084
00085
00086 if (accum->entryallocator == NULL || accum->eas_used >= DEF_NENTRY)
00087 {
00088 accum->entryallocator = palloc(sizeof(GinEntryAccumulator) * DEF_NENTRY);
00089 accum->allocatedMemory += GetMemoryChunkSpace(accum->entryallocator);
00090 accum->eas_used = 0;
00091 }
00092
00093
00094 ea = accum->entryallocator + accum->eas_used;
00095 accum->eas_used++;
00096
00097 return (RBNode *) ea;
00098 }
00099
00100 void
00101 ginInitBA(BuildAccumulator *accum)
00102 {
00103
00104 accum->allocatedMemory = 0;
00105 accum->entryallocator = NULL;
00106 accum->eas_used = 0;
00107 accum->tree = rb_create(sizeof(GinEntryAccumulator),
00108 cmpEntryAccumulator,
00109 ginCombineData,
00110 ginAllocEntryAccumulator,
00111 NULL,
00112 (void *) accum);
00113 }
00114
00115
00116
00117
00118
00119 static Datum
00120 getDatumCopy(BuildAccumulator *accum, OffsetNumber attnum, Datum value)
00121 {
00122 Form_pg_attribute att = accum->ginstate->origTupdesc->attrs[attnum - 1];
00123 Datum res;
00124
00125 if (att->attbyval)
00126 res = value;
00127 else
00128 {
00129 res = datumCopy(value, false, att->attlen);
00130 accum->allocatedMemory += GetMemoryChunkSpace(DatumGetPointer(res));
00131 }
00132 return res;
00133 }
00134
00135
00136
00137
00138 static void
00139 ginInsertBAEntry(BuildAccumulator *accum,
00140 ItemPointer heapptr, OffsetNumber attnum,
00141 Datum key, GinNullCategory category)
00142 {
00143 GinEntryAccumulator eatmp;
00144 GinEntryAccumulator *ea;
00145 bool isNew;
00146
00147
00148
00149
00150
00151 eatmp.attnum = attnum;
00152 eatmp.key = key;
00153 eatmp.category = category;
00154
00155 eatmp.list = heapptr;
00156
00157 ea = (GinEntryAccumulator *) rb_insert(accum->tree, (RBNode *) &eatmp,
00158 &isNew);
00159
00160 if (isNew)
00161 {
00162
00163
00164
00165
00166 if (category == GIN_CAT_NORM_KEY)
00167 ea->key = getDatumCopy(accum, attnum, key);
00168 ea->maxcount = DEF_NPTR;
00169 ea->count = 1;
00170 ea->shouldSort = FALSE;
00171 ea->list =
00172 (ItemPointerData *) palloc(sizeof(ItemPointerData) * DEF_NPTR);
00173 ea->list[0] = *heapptr;
00174 accum->allocatedMemory += GetMemoryChunkSpace(ea->list);
00175 }
00176 else
00177 {
00178
00179
00180
00181 }
00182 }
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200 void
00201 ginInsertBAEntries(BuildAccumulator *accum,
00202 ItemPointer heapptr, OffsetNumber attnum,
00203 Datum *entries, GinNullCategory *categories,
00204 int32 nentries)
00205 {
00206 uint32 step = nentries;
00207
00208 if (nentries <= 0)
00209 return;
00210
00211 Assert(ItemPointerIsValid(heapptr) && attnum >= FirstOffsetNumber);
00212
00213
00214
00215
00216 step |= (step >> 1);
00217 step |= (step >> 2);
00218 step |= (step >> 4);
00219 step |= (step >> 8);
00220 step |= (step >> 16);
00221 step >>= 1;
00222 step++;
00223
00224 while (step > 0)
00225 {
00226 int i;
00227
00228 for (i = step - 1; i < nentries && i >= 0; i += step << 1 )
00229 ginInsertBAEntry(accum, heapptr, attnum,
00230 entries[i], categories[i]);
00231
00232 step >>= 1;
00233 }
00234 }
00235
00236 static int
00237 qsortCompareItemPointers(const void *a, const void *b)
00238 {
00239 int res = ginCompareItemPointers((ItemPointer) a, (ItemPointer) b);
00240
00241
00242 Assert(res != 0);
00243 return res;
00244 }
00245
00246
00247 void
00248 ginBeginBAScan(BuildAccumulator *accum)
00249 {
00250 rb_begin_iterate(accum->tree, LeftRightWalk);
00251 }
00252
00253
00254
00255
00256
00257
00258 ItemPointerData *
00259 ginGetBAEntry(BuildAccumulator *accum,
00260 OffsetNumber *attnum, Datum *key, GinNullCategory *category,
00261 uint32 *n)
00262 {
00263 GinEntryAccumulator *entry;
00264 ItemPointerData *list;
00265
00266 entry = (GinEntryAccumulator *) rb_iterate(accum->tree);
00267
00268 if (entry == NULL)
00269 return NULL;
00270
00271 *attnum = entry->attnum;
00272 *key = entry->key;
00273 *category = entry->category;
00274 list = entry->list;
00275 *n = entry->count;
00276
00277 Assert(list != NULL && entry->count > 0);
00278
00279 if (entry->shouldSort && entry->count > 1)
00280 qsort(list, entry->count, sizeof(ItemPointerData),
00281 qsortCompareItemPointers);
00282
00283 return list;
00284 }