/* ** The GiST Penalty method for segments ** As in the R-tree paper, we use change in area as our penalty metric */ float * gseg_penalty(GISTENTRY *origentry, GISTENTRY *newentry, float *result) { SEG *ud; float tmp1, tmp2; ud = seg_union((SEG *) DatumGetPointer(origentry->key), (SEG *) DatumGetPointer(newentry->key)); rt_seg_size(ud, &tmp1); rt_seg_size((SEG *) DatumGetPointer(origentry->key), &tmp2); *result = tmp1 - tmp2; #ifdef GIST_DEBUG fprintf(stderr, "penalty\n"); fprintf(stderr, "\t%g\n", *result); #endif return (result); }
/* ** The GiST PickSplit method for segments ** We use Guttman's poly time split algorithm */ GIST_SPLITVEC * gseg_picksplit(GistEntryVector *entryvec, GIST_SPLITVEC *v) { OffsetNumber i, j; SEG *datum_alpha, *datum_beta; SEG *datum_l, *datum_r; SEG *union_d, *union_dl, *union_dr; SEG *inter_d; bool firsttime; float size_alpha, size_beta, size_union, size_inter; float size_waste, waste; float size_l, size_r; int nbytes; OffsetNumber seed_1 = 1, seed_2 = 2; OffsetNumber *left, *right; OffsetNumber maxoff; #ifdef GIST_DEBUG fprintf(stderr, "picksplit\n"); #endif maxoff = entryvec->n - 2; nbytes = (maxoff + 2) * sizeof(OffsetNumber); v->spl_left = (OffsetNumber *) palloc(nbytes); v->spl_right = (OffsetNumber *) palloc(nbytes); firsttime = true; waste = 0.0; for (i = FirstOffsetNumber; i < maxoff; i = OffsetNumberNext(i)) { datum_alpha = (SEG *) DatumGetPointer(entryvec->vector[i].key); for (j = OffsetNumberNext(i); j <= maxoff; j = OffsetNumberNext(j)) { datum_beta = (SEG *) DatumGetPointer(entryvec->vector[j].key); /* compute the wasted space by unioning these guys */ /* size_waste = size_union - size_inter; */ union_d = seg_union(datum_alpha, datum_beta); rt_seg_size(union_d, &size_union); inter_d = seg_inter(datum_alpha, datum_beta); rt_seg_size(inter_d, &size_inter); size_waste = size_union - size_inter; /* * are these a more promising split that what we've already seen? */ if (size_waste > waste || firsttime) { waste = size_waste; seed_1 = i; seed_2 = j; firsttime = false; } } } left = v->spl_left; v->spl_nleft = 0; right = v->spl_right; v->spl_nright = 0; datum_alpha = (SEG *) DatumGetPointer(entryvec->vector[seed_1].key); datum_l = seg_union(datum_alpha, datum_alpha); rt_seg_size(datum_l, &size_l); datum_beta = (SEG *) DatumGetPointer(entryvec->vector[seed_2].key); datum_r = seg_union(datum_beta, datum_beta); rt_seg_size(datum_r, &size_r); /* * Now split up the regions between the two seeds. An important property * of this split algorithm is that the split vector v has the indices of * items to be split in order in its left and right vectors. We exploit * this property by doing a merge in the code that actually splits the * page. * * For efficiency, we also place the new index tuple in this loop. This is * handled at the very end, when we have placed all the existing tuples * and i == maxoff + 1. */ maxoff = OffsetNumberNext(maxoff); for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) { /* * If we've already decided where to place this item, just put it on * the right list. Otherwise, we need to figure out which page needs * the least enlargement in order to store the item. */ if (i == seed_1) { *left++ = i; v->spl_nleft++; continue; } else if (i == seed_2) { *right++ = i; v->spl_nright++; continue; } /* okay, which page needs least enlargement? */ datum_alpha = (SEG *) DatumGetPointer(entryvec->vector[i].key); union_dl = seg_union(datum_l, datum_alpha); union_dr = seg_union(datum_r, datum_alpha); rt_seg_size(union_dl, &size_alpha); rt_seg_size(union_dr, &size_beta); /* pick which page to add it to */ if (size_alpha - size_l < size_beta - size_r) { datum_l = union_dl; size_l = size_alpha; *left++ = i; v->spl_nleft++; } else { datum_r = union_dr; size_r = size_alpha; *right++ = i; v->spl_nright++; } } *left = *right = FirstOffsetNumber; /* sentinel value, see dosplit() */ v->spl_ldatum = PointerGetDatum(datum_l); v->spl_rdatum = PointerGetDatum(datum_r); return v; }