LTP GCOV extension - code coverage report
Current view: directory - access/gist - gistutil.c
Test: unnamed
Date: 2008-07-03 Instrumented lines: 226
Code covered: 81.9 % Executed lines: 185
Legend: not executed executed

       1                 : /*-------------------------------------------------------------------------
       2                 :  *
       3                 :  * gistutil.c
       4                 :  *        utilities routines for the postgres GiST index access method.
       5                 :  *
       6                 :  *
       7                 :  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
       8                 :  * Portions Copyright (c) 1994, Regents of the University of California
       9                 :  *
      10                 :  * IDENTIFICATION
      11                 :  *                      $PostgreSQL: pgsql/src/backend/access/gist/gistutil.c,v 1.24 2007/09/20 17:56:30 tgl Exp $
      12                 :  *-------------------------------------------------------------------------
      13                 :  */
      14                 : #include "postgres.h"
      15                 : 
      16                 : #include "access/gist_private.h"
      17                 : #include "access/heapam.h"
      18                 : #include "access/reloptions.h"
      19                 : #include "storage/freespace.h"
      20                 : 
      21                 : /*
      22                 :  * static *S used for temrorary storage (saves stack and palloc() call)
      23                 :  */
      24                 : 
      25                 : static Datum attrS[INDEX_MAX_KEYS];
      26                 : static bool isnullS[INDEX_MAX_KEYS];
      27                 : 
      28                 : /*
      29                 :  * Write itup vector to page, has no control of free space
      30                 :  */
      31                 : OffsetNumber
      32                 : gistfillbuffer(Relation r, Page page, IndexTuple *itup,
      33                 :                            int len, OffsetNumber off)
      34           11496 : {
      35           11496 :         OffsetNumber l = InvalidOffsetNumber;
      36                 :         int                     i;
      37                 : 
      38           11496 :         if (off == InvalidOffsetNumber)
      39           11492 :                 off = (PageIsEmpty(page)) ? FirstOffsetNumber :
      40                 :                         OffsetNumberNext(PageGetMaxOffsetNumber(page));
      41                 : 
      42           23101 :         for (i = 0; i < len; i++)
      43                 :         {
      44           11605 :                 l = PageAddItem(page, (Item) itup[i], IndexTupleSize(itup[i]),
      45                 :                                                 off, false, false);
      46           11605 :                 if (l == InvalidOffsetNumber)
      47               0 :                         elog(ERROR, "failed to add item to index page in \"%s\"",
      48                 :                                  RelationGetRelationName(r));
      49           11605 :                 off++;
      50                 :         }
      51           11496 :         return l;
      52                 : }
      53                 : 
      54                 : /*
      55                 :  * Check space for itup vector on page
      56                 :  */
      57                 : bool
      58                 : gistnospace(Page page, IndexTuple *itvec, int len, OffsetNumber todelete, Size freespace)
      59           11601 : {
      60           11601 :         unsigned int size = freespace,
      61           11601 :                                 deleted = 0;
      62                 :         int                     i;
      63                 : 
      64           23307 :         for (i = 0; i < len; i++)
      65           11706 :                 size += IndexTupleSize(itvec[i]) + sizeof(ItemIdData);
      66                 : 
      67           11601 :         if (todelete != InvalidOffsetNumber)
      68                 :         {
      69             945 :                 IndexTuple      itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, todelete));
      70                 : 
      71             945 :                 deleted = IndexTupleSize(itup) + sizeof(ItemIdData);
      72                 :         }
      73                 : 
      74           11601 :         return (PageGetFreeSpace(page) + deleted < size);
      75                 : }
      76                 : 
      77                 : bool
      78                 : gistfitpage(IndexTuple *itvec, int len)
      79             218 : {
      80                 :         int                     i;
      81             218 :         Size            size = 0;
      82                 : 
      83           15988 :         for (i = 0; i < len; i++)
      84           15770 :                 size += IndexTupleSize(itvec[i]) + sizeof(ItemIdData);
      85                 : 
      86                 :         /* TODO: Consider fillfactor */
      87             218 :         return (size <= GiSTPageSize);
      88                 : }
      89                 : 
      90                 : /*
      91                 :  * Read buffer into itup vector
      92                 :  */
      93                 : IndexTuple *
      94                 : gistextractpage(Page page, int *len /* out */ )
      95             109 : {
      96                 :         OffsetNumber i,
      97                 :                                 maxoff;
      98                 :         IndexTuple *itvec;
      99                 : 
     100             109 :         maxoff = PageGetMaxOffsetNumber(page);
     101             109 :         *len = maxoff;
     102             109 :         itvec = palloc(sizeof(IndexTuple) * maxoff);
     103           15770 :         for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
     104           15661 :                 itvec[i - FirstOffsetNumber] = (IndexTuple) PageGetItem(page, PageGetItemId(page, i));
     105                 : 
     106             109 :         return itvec;
     107                 : }
     108                 : 
     109                 : /*
     110                 :  * join two vectors into one
     111                 :  */
     112                 : IndexTuple *
     113                 : gistjoinvector(IndexTuple *itvec, int *len, IndexTuple *additvec, int addlen)
     114             109 : {
     115             109 :         itvec = (IndexTuple *) repalloc((void *) itvec, sizeof(IndexTuple) * ((*len) + addlen));
     116             109 :         memmove(&itvec[*len], additvec, sizeof(IndexTuple) * addlen);
     117             109 :         *len += addlen;
     118             109 :         return itvec;
     119                 : }
     120                 : 
     121                 : /*
     122                 :  * make plain IndexTupleVector
     123                 :  */
     124                 : 
     125                 : IndexTupleData *
     126                 : gistfillitupvec(IndexTuple *vec, int veclen, int *memlen)
     127             218 : {
     128                 :         char       *ptr,
     129                 :                            *ret;
     130                 :         int                     i;
     131                 : 
     132             218 :         *memlen = 0;
     133                 : 
     134           15988 :         for (i = 0; i < veclen; i++)
     135           15770 :                 *memlen += IndexTupleSize(vec[i]);
     136                 : 
     137             218 :         ptr = ret = palloc(*memlen);
     138                 : 
     139           15988 :         for (i = 0; i < veclen; i++)
     140                 :         {
     141           15770 :                 memcpy(ptr, vec[i], IndexTupleSize(vec[i]));
     142           15770 :                 ptr += IndexTupleSize(vec[i]);
     143                 :         }
     144                 : 
     145             218 :         return (IndexTupleData *) ret;
     146                 : }
     147                 : 
     148                 : /*
     149                 :  * Make unions of keys in IndexTuple vector, return FALSE if itvec contains
     150                 :  * invalid tuple. Resulting Datums aren't compressed.
     151                 :  */
     152                 : 
     153                 : bool
     154                 : gistMakeUnionItVec(GISTSTATE *giststate, IndexTuple *itvec, int len, int startkey,
     155                 :                                    Datum *attr, bool *isnull)
     156             111 : {
     157                 :         int                     i;
     158                 :         GistEntryVector *evec;
     159                 :         int                     attrsize;
     160                 : 
     161             111 :         evec = (GistEntryVector *) palloc((len + 2) * sizeof(GISTENTRY) + GEVHDRSZ);
     162                 : 
     163             222 :         for (i = startkey; i < giststate->tupdesc->natts; i++)
     164                 :         {
     165                 :                 int                     j;
     166                 : 
     167             111 :                 evec->n = 0;
     168             111 :                 if (!isnull[i])
     169                 :                 {
     170               0 :                         gistentryinit(evec->vector[evec->n], attr[i],
     171                 :                                                   NULL, NULL, (OffsetNumber) 0,
     172                 :                                                   FALSE);
     173               0 :                         evec->n++;
     174                 :                 }
     175                 : 
     176             846 :                 for (j = 0; j < len; j++)
     177                 :                 {
     178                 :                         Datum           datum;
     179                 :                         bool            IsNull;
     180                 : 
     181             735 :                         if (GistTupleIsInvalid(itvec[j]))
     182               0 :                                 return FALSE;   /* signals that union with invalid tuple =>
     183                 :                                                                  * result is invalid */
     184                 : 
     185             735 :                         datum = index_getattr(itvec[j], i + 1, giststate->tupdesc, &IsNull);
     186             735 :                         if (IsNull)
     187              36 :                                 continue;
     188                 : 
     189             699 :                         gistdentryinit(giststate, i,
     190                 :                                                    evec->vector + evec->n,
     191                 :                                                    datum,
     192                 :                                                    NULL, NULL, (OffsetNumber) 0,
     193                 :                                                    FALSE, IsNull);
     194             699 :                         evec->n++;
     195                 :                 }
     196                 : 
     197                 :                 /* If this tuple vector was all NULLs, the union is NULL */
     198             111 :                 if (evec->n == 0)
     199                 :                 {
     200               3 :                         attr[i] = (Datum) 0;
     201               3 :                         isnull[i] = TRUE;
     202                 :                 }
     203                 :                 else
     204                 :                 {
     205             108 :                         if (evec->n == 1)
     206                 :                         {
     207               0 :                                 evec->n = 2;
     208               0 :                                 evec->vector[1] = evec->vector[0];
     209                 :                         }
     210                 : 
     211                 :                         /* Make union and store in attr array */
     212             108 :                         attr[i] = FunctionCall2(&giststate->unionFn[i],
     213                 :                                                                         PointerGetDatum(evec),
     214                 :                                                                         PointerGetDatum(&attrsize));
     215                 : 
     216             108 :                         isnull[i] = FALSE;
     217                 :                 }
     218                 :         }
     219                 : 
     220             111 :         return TRUE;
     221                 : }
     222                 : 
     223                 : /*
     224                 :  * Return an IndexTuple containing the result of applying the "union"
     225                 :  * method to the specified IndexTuple vector.
     226                 :  */
     227                 : IndexTuple
     228                 : gistunion(Relation r, IndexTuple *itvec, int len, GISTSTATE *giststate)
     229             105 : {
     230             105 :         memset(isnullS, TRUE, sizeof(bool) * giststate->tupdesc->natts);
     231                 : 
     232             105 :         if (!gistMakeUnionItVec(giststate, itvec, len, 0, attrS, isnullS))
     233               0 :                 return gist_form_invalid_tuple(InvalidBlockNumber);
     234                 : 
     235             105 :         return gistFormTuple(giststate, r, attrS, isnullS, false);
     236                 : }
     237                 : 
     238                 : /*
     239                 :  * makes union of two key
     240                 :  */
     241                 : void
     242                 : gistMakeUnionKey(GISTSTATE *giststate, int attno,
     243                 :                                  GISTENTRY *entry1, bool isnull1,
     244                 :                                  GISTENTRY *entry2, bool isnull2,
     245                 :                                  Datum *dst, bool *dstisnull)
     246            9973 : {
     247                 : 
     248                 :         int                     dstsize;
     249                 : 
     250                 :         static char storage[2 * sizeof(GISTENTRY) + GEVHDRSZ];
     251            9973 :         GistEntryVector *evec = (GistEntryVector *) storage;
     252                 : 
     253            9973 :         evec->n = 2;
     254                 : 
     255            9973 :         if (isnull1 && isnull2)
     256                 :         {
     257             798 :                 *dstisnull = TRUE;
     258             798 :                 *dst = (Datum) 0;
     259                 :         }
     260                 :         else
     261                 :         {
     262            9175 :                 if (isnull1 == FALSE && isnull2 == FALSE)
     263                 :                 {
     264            9175 :                         evec->vector[0] = *entry1;
     265            9175 :                         evec->vector[1] = *entry2;
     266                 :                 }
     267               0 :                 else if (isnull1 == FALSE)
     268                 :                 {
     269               0 :                         evec->vector[0] = *entry1;
     270               0 :                         evec->vector[1] = *entry1;
     271                 :                 }
     272                 :                 else
     273                 :                 {
     274               0 :                         evec->vector[0] = *entry2;
     275               0 :                         evec->vector[1] = *entry2;
     276                 :                 }
     277                 : 
     278            9175 :                 *dstisnull = FALSE;
     279            9175 :                 *dst = FunctionCall2(&giststate->unionFn[attno],
     280                 :                                                          PointerGetDatum(evec),
     281                 :                                                          PointerGetDatum(&dstsize));
     282                 :         }
     283            9973 : }
     284                 : 
     285                 : bool
     286                 : gistKeyIsEQ(GISTSTATE *giststate, int attno, Datum a, Datum b)
     287            9175 : {
     288                 :         bool            result;
     289                 : 
     290            9175 :         FunctionCall3(&giststate->equalFn[attno],
     291                 :                                   a, b,
     292                 :                                   PointerGetDatum(&result));
     293            9175 :         return result;
     294                 : }
     295                 : 
     296                 : /*
     297                 :  * Decompress all keys in tuple
     298                 :  */
     299                 : void
     300                 : gistDeCompressAtt(GISTSTATE *giststate, Relation r, IndexTuple tuple, Page p,
     301                 :                                   OffsetNumber o, GISTENTRY *attdata, bool *isnull)
     302           30024 : {
     303                 :         int                     i;
     304                 : 
     305           60048 :         for (i = 0; i < r->rd_att->natts; i++)
     306                 :         {
     307           30024 :                 Datum           datum = index_getattr(tuple, i + 1, giststate->tupdesc, &isnull[i]);
     308                 : 
     309           30024 :                 gistdentryinit(giststate, i, &attdata[i],
     310                 :                                            datum, r, p, o,
     311                 :                                            FALSE, isnull[i]);
     312                 :         }
     313           30024 : }
     314                 : 
     315                 : /*
     316                 :  * Forms union of oldtup and addtup, if union == oldtup then return NULL
     317                 :  */
     318                 : IndexTuple
     319                 : gistgetadjusted(Relation r, IndexTuple oldtup, IndexTuple addtup, GISTSTATE *giststate)
     320            9973 : {
     321            9973 :         bool            neednew = FALSE;
     322                 :         GISTENTRY       oldentries[INDEX_MAX_KEYS],
     323                 :                                 addentries[INDEX_MAX_KEYS];
     324                 :         bool            oldisnull[INDEX_MAX_KEYS],
     325                 :                                 addisnull[INDEX_MAX_KEYS];
     326            9973 :         IndexTuple      newtup = NULL;
     327                 :         int                     i;
     328                 : 
     329            9973 :         if (GistTupleIsInvalid(oldtup) || GistTupleIsInvalid(addtup))
     330               0 :                 return gist_form_invalid_tuple(ItemPointerGetBlockNumber(&(oldtup->t_tid)));
     331                 : 
     332            9973 :         gistDeCompressAtt(giststate, r, oldtup, NULL,
     333                 :                                           (OffsetNumber) 0, oldentries, oldisnull);
     334                 : 
     335            9973 :         gistDeCompressAtt(giststate, r, addtup, NULL,
     336                 :                                           (OffsetNumber) 0, addentries, addisnull);
     337                 : 
     338           19946 :         for (i = 0; i < r->rd_att->natts; i++)
     339                 :         {
     340            9973 :                 gistMakeUnionKey(giststate, i,
     341                 :                                                  oldentries + i, oldisnull[i],
     342                 :                                                  addentries + i, addisnull[i],
     343                 :                                                  attrS + i, isnullS + i);
     344                 : 
     345            9973 :                 if (neednew)
     346                 :                         /* we already need new key, so we can skip check */
     347               0 :                         continue;
     348                 : 
     349            9973 :                 if (isnullS[i])
     350                 :                         /* union of key may be NULL if and only if both keys are NULL */
     351             798 :                         continue;
     352                 : 
     353            9175 :                 if (!addisnull[i])
     354                 :                 {
     355            9175 :                         if (oldisnull[i] || gistKeyIsEQ(giststate, i, oldentries[i].key, attrS[i]) == false)
     356             840 :                                 neednew = true;
     357                 :                 }
     358                 :         }
     359                 : 
     360            9973 :         if (neednew)
     361                 :         {
     362                 :                 /* need to update key */
     363             840 :                 newtup = gistFormTuple(giststate, r, attrS, isnullS, false);
     364             840 :                 newtup->t_tid = oldtup->t_tid;
     365                 :         }
     366                 : 
     367            9973 :         return newtup;
     368                 : }
     369                 : 
     370                 : /*
     371                 :  * find entry with lowest penalty
     372                 :  */
     373                 : OffsetNumber
     374                 : gistchoose(Relation r, Page p, IndexTuple it,   /* it has compressed entry */
     375                 :                    GISTSTATE *giststate)
     376           10078 : {
     377                 :         OffsetNumber maxoff;
     378                 :         OffsetNumber i;
     379                 :         OffsetNumber which;
     380                 :         float           sum_grow,
     381                 :                                 which_grow[INDEX_MAX_KEYS];
     382                 :         GISTENTRY       entry,
     383                 :                                 identry[INDEX_MAX_KEYS];
     384                 :         bool            isnull[INDEX_MAX_KEYS];
     385                 : 
     386           10078 :         maxoff = PageGetMaxOffsetNumber(p);
     387           10078 :         *which_grow = -1.0;
     388           10078 :         which = InvalidOffsetNumber;
     389           10078 :         sum_grow = 1;
     390           10078 :         gistDeCompressAtt(giststate, r,
     391                 :                                           it, NULL, (OffsetNumber) 0,
     392                 :                                           identry, isnull);
     393                 : 
     394                 :         Assert(maxoff >= FirstOffsetNumber);
     395                 :         Assert(!GistPageIsLeaf(p));
     396                 : 
     397          118727 :         for (i = FirstOffsetNumber; i <= maxoff && sum_grow; i = OffsetNumberNext(i))
     398                 :         {
     399                 :                 int                     j;
     400          108649 :                 IndexTuple      itup = (IndexTuple) PageGetItem(p, PageGetItemId(p, i));
     401                 : 
     402          108649 :                 if (!GistPageIsLeaf(p) && GistTupleIsInvalid(itup))
     403                 :                 {
     404               0 :                         ereport(LOG,
     405                 :                                         (errmsg("index \"%s\" needs VACUUM or REINDEX to finish crash recovery",
     406                 :                                                         RelationGetRelationName(r))));
     407                 :                         continue;
     408                 :                 }
     409                 : 
     410          108649 :                 sum_grow = 0;
     411          172038 :                 for (j = 0; j < r->rd_att->natts; j++)
     412                 :                 {
     413                 :                         Datum           datum;
     414                 :                         float           usize;
     415                 :                         bool            IsNull;
     416                 : 
     417          108649 :                         datum = index_getattr(itup, j + 1, giststate->tupdesc, &IsNull);
     418          108649 :                         gistdentryinit(giststate, j, &entry, datum, r, p, i,
     419                 :                                                    FALSE, IsNull);
     420          108649 :                         usize = gistpenalty(giststate, j, &entry, IsNull,
     421                 :                                                                 &identry[j], isnull[j]);
     422                 : 
     423          171729 :                         if (which_grow[j] < 0 || usize < which_grow[j])
     424                 :                         {
     425           63080 :                                 which = i;
     426           63080 :                                 which_grow[j] = usize;
     427           63080 :                                 if (j < r->rd_att->natts - 1 && i == FirstOffsetNumber)
     428               0 :                                         which_grow[j + 1] = -1;
     429           63080 :                                 sum_grow += which_grow[j];
     430                 :                         }
     431           45569 :                         else if (which_grow[j] == usize)
     432             309 :                                 sum_grow += usize;
     433                 :                         else
     434                 :                         {
     435           45260 :                                 sum_grow = 1;
     436           45260 :                                 break;
     437                 :                         }
     438                 :                 }
     439                 :         }
     440                 : 
     441           10078 :         if (which == InvalidOffsetNumber)
     442               0 :                 which = FirstOffsetNumber;
     443                 : 
     444           10078 :         return which;
     445                 : }
     446                 : 
     447                 : /*
     448                 :  * initialize a GiST entry with a decompressed version of key
     449                 :  */
     450                 : void
     451                 : gistdentryinit(GISTSTATE *giststate, int nkey, GISTENTRY *e,
     452                 :                            Datum k, Relation r, Page pg, OffsetNumber o,
     453                 :                            bool l, bool isNull)
     454          159241 : {
     455          159241 :         if (!isNull)
     456                 :         {
     457                 :                 GISTENTRY  *dep;
     458                 : 
     459          147210 :                 gistentryinit(*e, k, r, pg, o, l);
     460          147210 :                 dep = (GISTENTRY *)
     461                 :                         DatumGetPointer(FunctionCall1(&giststate->decompressFn[nkey],
     462                 :                                                                                   PointerGetDatum(e)));
     463                 :                 /* decompressFn may just return the given pointer */
     464          147210 :                 if (dep != e)
     465               0 :                         gistentryinit(*e, dep->key, dep->rel, dep->page, dep->offset,
     466                 :                                                   dep->leafkey);
     467                 :         }
     468                 :         else
     469           12031 :                 gistentryinit(*e, (Datum) 0, r, pg, o, l);
     470          159241 : }
     471                 : 
     472                 : 
     473                 : /*
     474                 :  * initialize a GiST entry with a compressed version of key
     475                 :  */
     476                 : void
     477                 : gistcentryinit(GISTSTATE *giststate, int nkey,
     478                 :                            GISTENTRY *e, Datum k, Relation r,
     479                 :                            Page pg, OffsetNumber o, bool l, bool isNull)
     480           10982 : {
     481           10982 :         if (!isNull)
     482                 :         {
     483                 :                 GISTENTRY  *cep;
     484                 : 
     485           10982 :                 gistentryinit(*e, k, r, pg, o, l);
     486           10982 :                 cep = (GISTENTRY *)
     487                 :                         DatumGetPointer(FunctionCall1(&giststate->compressFn[nkey],
     488                 :                                                                                   PointerGetDatum(e)));
     489                 :                 /* compressFn may just return the given pointer */
     490           10982 :                 if (cep != e)
     491            6722 :                         gistentryinit(*e, cep->key, cep->rel, cep->page, cep->offset,
     492                 :                                                   cep->leafkey);
     493                 :         }
     494                 :         else
     495               0 :                 gistentryinit(*e, (Datum) 0, r, pg, o, l);
     496           10982 : }
     497                 : 
     498                 : IndexTuple
     499                 : gistFormTuple(GISTSTATE *giststate, Relation r,
     500                 :                           Datum attdata[], bool isnull[], bool newValues)
     501           11819 : {
     502                 :         GISTENTRY       centry[INDEX_MAX_KEYS];
     503                 :         Datum           compatt[INDEX_MAX_KEYS];
     504                 :         int                     i;
     505                 :         IndexTuple      res;
     506                 : 
     507           23638 :         for (i = 0; i < r->rd_att->natts; i++)
     508                 :         {
     509           11819 :                 if (isnull[i])
     510             837 :                         compatt[i] = (Datum) 0;
     511                 :                 else
     512                 :                 {
     513           10982 :                         gistcentryinit(giststate, i, &centry[i], attdata[i],
     514                 :                                                    r, NULL, (OffsetNumber) 0,
     515                 :                                                    newValues,
     516                 :                                                    FALSE);
     517           10982 :                         compatt[i] = centry[i].key;
     518                 :                 }
     519                 :         }
     520                 : 
     521           11819 :         res = index_form_tuple(giststate->tupdesc, compatt, isnull);
     522           11819 :         GistTupleSetValid(res);
     523           11819 :         return res;
     524                 : }
     525                 : 
     526                 : float
     527                 : gistpenalty(GISTSTATE *giststate, int attno,
     528                 :                         GISTENTRY *orig, bool isNullOrig,
     529                 :                         GISTENTRY *add, bool isNullAdd)
     530          108649 : {
     531          108649 :         float           penalty = 0.0;
     532                 : 
     533          207697 :         if (giststate->penaltyFn[attno].fn_strict == FALSE || (isNullOrig == FALSE && isNullAdd == FALSE))
     534           99048 :                 FunctionCall3(&giststate->penaltyFn[attno],
     535                 :                                           PointerGetDatum(orig),
     536                 :                                           PointerGetDatum(add),
     537                 :                                           PointerGetDatum(&penalty));
     538            9601 :         else if (isNullOrig && isNullAdd)
     539             798 :                 penalty = 0.0;
     540                 :         else
     541            8803 :                 penalty = 1e10;                 /* try to prevent to mix null and non-null
     542                 :                                                                  * value */
     543                 : 
     544          108649 :         return penalty;
     545                 : }
     546                 : 
     547                 : /*
     548                 :  * Initialize a new index page
     549                 :  */
     550                 : void
     551                 : GISTInitBuffer(Buffer b, uint32 f)
     552             124 : {
     553                 :         GISTPageOpaque opaque;
     554                 :         Page            page;
     555                 :         Size            pageSize;
     556                 : 
     557             124 :         pageSize = BufferGetPageSize(b);
     558             124 :         page = BufferGetPage(b);
     559             124 :         PageInit(page, pageSize, sizeof(GISTPageOpaqueData));
     560                 : 
     561             124 :         opaque = GistPageGetOpaque(page);
     562                 :         /* page was already zeroed by PageInit, so this is not needed: */
     563                 :         /* memset(&(opaque->nsn), 0, sizeof(GistNSN)); */
     564             124 :         opaque->rightlink = InvalidBlockNumber;
     565             124 :         opaque->flags = f;
     566             124 :         opaque->gist_page_id = GIST_PAGE_ID;
     567             124 : }
     568                 : 
     569                 : /*
     570                 :  * Verify that a freshly-read page looks sane.
     571                 :  */
     572                 : void
     573                 : gistcheckpage(Relation rel, Buffer buf)
     574           31332 : {
     575           31332 :         Page            page = BufferGetPage(buf);
     576                 : 
     577                 :         /*
     578                 :          * ReadBuffer verifies that every newly-read page passes
     579                 :          * PageHeaderIsValid, which means it either contains a reasonably sane
     580                 :          * page header or is all-zero.  We have to defend against the all-zero
     581                 :          * case, however.
     582                 :          */
     583           31332 :         if (PageIsNew(page))
     584               0 :                 ereport(ERROR,
     585                 :                                 (errcode(ERRCODE_INDEX_CORRUPTED),
     586                 :                          errmsg("index \"%s\" contains unexpected zero page at block %u",
     587                 :                                         RelationGetRelationName(rel),
     588                 :                                         BufferGetBlockNumber(buf)),
     589                 :                                  errhint("Please REINDEX it.")));
     590                 : 
     591                 :         /*
     592                 :          * Additionally check that the special area looks sane.
     593                 :          */
     594           31332 :         if (((PageHeader) (page))->pd_special !=
     595                 :                 (BLCKSZ - MAXALIGN(sizeof(GISTPageOpaqueData))))
     596               0 :                 ereport(ERROR,
     597                 :                                 (errcode(ERRCODE_INDEX_CORRUPTED),
     598                 :                                  errmsg("index \"%s\" contains corrupted page at block %u",
     599                 :                                                 RelationGetRelationName(rel),
     600                 :                                                 BufferGetBlockNumber(buf)),
     601                 :                                  errhint("Please REINDEX it.")));
     602           31332 : }
     603                 : 
     604                 : 
     605                 : /*
     606                 :  * Allocate a new page (either by recycling, or by extending the index file)
     607                 :  *
     608                 :  * The returned buffer is already pinned and exclusive-locked
     609                 :  *
     610                 :  * Caller is responsible for initializing the page by calling GISTInitBuffer
     611                 :  */
     612                 : Buffer
     613                 : gistNewBuffer(Relation r)
     614             120 : {
     615                 :         Buffer          buffer;
     616                 :         bool            needLock;
     617                 : 
     618                 :         /* First, try to get a page from FSM */
     619                 :         for (;;)
     620                 :         {
     621             120 :                 BlockNumber blkno = GetFreeIndexPage(&r->rd_node);
     622                 : 
     623             120 :                 if (blkno == InvalidBlockNumber)
     624             120 :                         break;                          /* nothing left in FSM */
     625                 : 
     626               0 :                 buffer = ReadBuffer(r, blkno);
     627                 : 
     628                 :                 /*
     629                 :                  * We have to guard against the possibility that someone else already
     630                 :                  * recycled this page; the buffer may be locked if so.
     631                 :                  */
     632               0 :                 if (ConditionalLockBuffer(buffer))
     633                 :                 {
     634               0 :                         Page            page = BufferGetPage(buffer);
     635                 : 
     636               0 :                         if (PageIsNew(page))
     637               0 :                                 return buffer;  /* OK to use, if never initialized */
     638                 : 
     639               0 :                         gistcheckpage(r, buffer);
     640                 : 
     641               0 :                         if (GistPageIsDeleted(page))
     642               0 :                                 return buffer;  /* OK to use */
     643                 : 
     644               0 :                         LockBuffer(buffer, GIST_UNLOCK);
     645                 :                 }
     646                 : 
     647                 :                 /* Can't use it, so release buffer and try again */
     648               0 :                 ReleaseBuffer(buffer);
     649               0 :         }
     650                 : 
     651                 :         /* Must extend the file */
     652             120 :         needLock = !RELATION_IS_LOCAL(r);
     653                 : 
     654             120 :         if (needLock)
     655               0 :                 LockRelationForExtension(r, ExclusiveLock);
     656                 : 
     657             120 :         buffer = ReadBuffer(r, P_NEW);
     658             120 :         LockBuffer(buffer, GIST_EXCLUSIVE);
     659                 : 
     660             120 :         if (needLock)
     661               0 :                 UnlockRelationForExtension(r, ExclusiveLock);
     662                 : 
     663             120 :         return buffer;
     664                 : }
     665                 : 
     666                 : Datum
     667                 : gistoptions(PG_FUNCTION_ARGS)
     668               0 : {
     669               0 :         Datum           reloptions = PG_GETARG_DATUM(0);
     670               0 :         bool            validate = PG_GETARG_BOOL(1);
     671                 :         bytea      *result;
     672                 : 
     673               0 :         result = default_reloptions(reloptions, validate,
     674                 :                                                                 GIST_MIN_FILLFACTOR,
     675                 :                                                                 GIST_DEFAULT_FILLFACTOR);
     676               0 :         if (result)
     677               0 :                 PG_RETURN_BYTEA_P(result);
     678               0 :         PG_RETURN_NULL();
     679                 : }

Generated by: LTP GCOV extension version 1.5