LTP GCOV extension - code coverage report
Current view: directory - access/hash - hashinsert.c
Test: unnamed
Date: 2008-07-03 Instrumented lines: 48
Code covered: 93.8 % Executed lines: 45
Legend: not executed executed

       1                 : /*-------------------------------------------------------------------------
       2                 :  *
       3                 :  * hashinsert.c
       4                 :  *        Item insertion in hash tables for Postgres.
       5                 :  *
       6                 :  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
       7                 :  * Portions Copyright (c) 1994, Regents of the University of California
       8                 :  *
       9                 :  *
      10                 :  * IDENTIFICATION
      11                 :  *        $PostgreSQL: pgsql/src/backend/access/hash/hashinsert.c,v 1.47 2007/09/20 17:56:30 tgl Exp $
      12                 :  *
      13                 :  *-------------------------------------------------------------------------
      14                 :  */
      15                 : 
      16                 : #include "postgres.h"
      17                 : 
      18                 : #include "access/hash.h"
      19                 : 
      20                 : 
      21                 : static OffsetNumber _hash_pgaddtup(Relation rel, Buffer buf,
      22                 :                            Size itemsize, IndexTuple itup);
      23                 : 
      24                 : 
      25                 : /*
      26                 :  *      _hash_doinsert() -- Handle insertion of a single index tuple.
      27                 :  *
      28                 :  *              This routine is called by the public interface routines, hashbuild
      29                 :  *              and hashinsert.  By here, itup is completely filled in.
      30                 :  */
      31                 : void
      32                 : _hash_doinsert(Relation rel, IndexTuple itup)
      33           40018 : {
      34                 :         Buffer          buf;
      35                 :         Buffer          metabuf;
      36                 :         HashMetaPage metap;
      37                 :         BlockNumber blkno;
      38                 :         Page            page;
      39                 :         HashPageOpaque pageopaque;
      40                 :         Size            itemsz;
      41                 :         bool            do_expand;
      42                 :         uint32          hashkey;
      43                 :         Bucket          bucket;
      44                 :         Datum           datum;
      45                 :         bool            isnull;
      46                 : 
      47                 :         /*
      48                 :          * Compute the hash key for the item.  We do this first so as not to need
      49                 :          * to hold any locks while running the hash function.
      50                 :          */
      51           40018 :         if (rel->rd_rel->relnatts != 1)
      52               0 :                 elog(ERROR, "hash indexes support only one index key");
      53           40018 :         datum = index_getattr(itup, 1, RelationGetDescr(rel), &isnull);
      54                 :         Assert(!isnull);
      55           40018 :         hashkey = _hash_datum2hashkey(rel, datum);
      56                 : 
      57                 :         /* compute item size too */
      58           40018 :         itemsz = IndexTupleDSize(*itup);
      59           40018 :         itemsz = MAXALIGN(itemsz);      /* be safe, PageAddItem will do this but we
      60                 :                                                                  * need to be consistent */
      61                 : 
      62                 :         /*
      63                 :          * Acquire shared split lock so we can compute the target bucket safely
      64                 :          * (see README).
      65                 :          */
      66           40018 :         _hash_getlock(rel, 0, HASH_SHARE);
      67                 : 
      68                 :         /* Read the metapage */
      69           40018 :         metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ, LH_META_PAGE);
      70           40018 :         metap = (HashMetaPage) BufferGetPage(metabuf);
      71                 : 
      72                 :         /*
      73                 :          * Check whether the item can fit on a hash page at all. (Eventually, we
      74                 :          * ought to try to apply TOAST methods if not.)  Note that at this point,
      75                 :          * itemsz doesn't include the ItemId.
      76                 :          */
      77           40018 :         if (itemsz > HashMaxItemSize((Page) metap))
      78               0 :                 ereport(ERROR,
      79                 :                                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
      80                 :                                  errmsg("index row size %lu exceeds hash maximum %lu",
      81                 :                                                 (unsigned long) itemsz,
      82                 :                                                 (unsigned long) HashMaxItemSize((Page) metap)),
      83                 :                         errhint("Values larger than a buffer page cannot be indexed.")));
      84                 : 
      85                 :         /*
      86                 :          * Compute the target bucket number, and convert to block number.
      87                 :          */
      88           40018 :         bucket = _hash_hashkey2bucket(hashkey,
      89                 :                                                                   metap->hashm_maxbucket,
      90                 :                                                                   metap->hashm_highmask,
      91                 :                                                                   metap->hashm_lowmask);
      92                 : 
      93           40018 :         blkno = BUCKET_TO_BLKNO(metap, bucket);
      94                 : 
      95                 :         /* release lock on metapage, but keep pin since we'll need it again */
      96           40018 :         _hash_chgbufaccess(rel, metabuf, HASH_READ, HASH_NOLOCK);
      97                 : 
      98                 :         /*
      99                 :          * Acquire share lock on target bucket; then we can release split lock.
     100                 :          */
     101           40018 :         _hash_getlock(rel, blkno, HASH_SHARE);
     102                 : 
     103           40018 :         _hash_droplock(rel, 0, HASH_SHARE);
     104                 : 
     105                 :         /* Fetch the primary bucket page for the bucket */
     106           40018 :         buf = _hash_getbuf(rel, blkno, HASH_WRITE, LH_BUCKET_PAGE);
     107           40018 :         page = BufferGetPage(buf);
     108           40018 :         pageopaque = (HashPageOpaque) PageGetSpecialPointer(page);
     109                 :         Assert(pageopaque->hasho_bucket == bucket);
     110                 : 
     111                 :         /* Do the insertion */
     112           85816 :         while (PageGetFreeSpace(page) < itemsz)
     113                 :         {
     114                 :                 /*
     115                 :                  * no space on this page; check for an overflow page
     116                 :                  */
     117            5780 :                 BlockNumber nextblkno = pageopaque->hasho_nextblkno;
     118                 : 
     119            5780 :                 if (BlockNumberIsValid(nextblkno))
     120                 :                 {
     121                 :                         /*
     122                 :                          * ovfl page exists; go get it.  if it doesn't have room, we'll
     123                 :                          * find out next pass through the loop test above.
     124                 :                          */
     125            5663 :                         _hash_relbuf(rel, buf);
     126            5663 :                         buf = _hash_getbuf(rel, nextblkno, HASH_WRITE, LH_OVERFLOW_PAGE);
     127            5663 :                         page = BufferGetPage(buf);
     128                 :                 }
     129                 :                 else
     130                 :                 {
     131                 :                         /*
     132                 :                          * we're at the end of the bucket chain and we haven't found a
     133                 :                          * page with enough room.  allocate a new overflow page.
     134                 :                          */
     135                 : 
     136                 :                         /* release our write lock without modifying buffer */
     137             117 :                         _hash_chgbufaccess(rel, buf, HASH_READ, HASH_NOLOCK);
     138                 : 
     139                 :                         /* chain to a new overflow page */
     140             117 :                         buf = _hash_addovflpage(rel, metabuf, buf);
     141             117 :                         page = BufferGetPage(buf);
     142                 : 
     143                 :                         /* should fit now, given test above */
     144                 :                         Assert(PageGetFreeSpace(page) >= itemsz);
     145                 :                 }
     146            5780 :                 pageopaque = (HashPageOpaque) PageGetSpecialPointer(page);
     147                 :                 Assert(pageopaque->hasho_flag == LH_OVERFLOW_PAGE);
     148                 :                 Assert(pageopaque->hasho_bucket == bucket);
     149                 :         }
     150                 : 
     151                 :         /* found page with enough space, so add the item here */
     152           40018 :         (void) _hash_pgaddtup(rel, buf, itemsz, itup);
     153                 : 
     154                 :         /* write and release the modified page */
     155           40018 :         _hash_wrtbuf(rel, buf);
     156                 : 
     157                 :         /* We can drop the bucket lock now */
     158           40018 :         _hash_droplock(rel, blkno, HASH_SHARE);
     159                 : 
     160                 :         /*
     161                 :          * Write-lock the metapage so we can increment the tuple count. After
     162                 :          * incrementing it, check to see if it's time for a split.
     163                 :          */
     164           40018 :         _hash_chgbufaccess(rel, metabuf, HASH_NOLOCK, HASH_WRITE);
     165                 : 
     166           40018 :         metap->hashm_ntuples += 1;
     167                 : 
     168                 :         /* Make sure this stays in sync with _hash_expandtable() */
     169           40018 :         do_expand = metap->hashm_ntuples >
     170                 :                 (double) metap->hashm_ffactor * (metap->hashm_maxbucket + 1);
     171                 : 
     172                 :         /* Write out the metapage and drop lock, but keep pin */
     173           40018 :         _hash_chgbufaccess(rel, metabuf, HASH_WRITE, HASH_NOLOCK);
     174                 : 
     175                 :         /* Attempt to split if a split is needed */
     176           40018 :         if (do_expand)
     177             250 :                 _hash_expandtable(rel, metabuf);
     178                 : 
     179                 :         /* Finally drop our pin on the metapage */
     180           40018 :         _hash_dropbuf(rel, metabuf);
     181           40018 : }
     182                 : 
     183                 : /*
     184                 :  *      _hash_pgaddtup() -- add a tuple to a particular page in the index.
     185                 :  *
     186                 :  *              This routine adds the tuple to the page as requested; it does
     187                 :  *              not write out the page.  It is an error to call pgaddtup() without
     188                 :  *              a write lock and pin.
     189                 :  */
     190                 : static OffsetNumber
     191                 : _hash_pgaddtup(Relation rel,
     192                 :                            Buffer buf,
     193                 :                            Size itemsize,
     194                 :                            IndexTuple itup)
     195           40018 : {
     196                 :         OffsetNumber itup_off;
     197                 :         Page            page;
     198                 : 
     199           40018 :         _hash_checkpage(rel, buf, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
     200           40018 :         page = BufferGetPage(buf);
     201                 : 
     202           40018 :         itup_off = OffsetNumberNext(PageGetMaxOffsetNumber(page));
     203           40018 :         if (PageAddItem(page, (Item) itup, itemsize, itup_off, false, false)
     204                 :                 == InvalidOffsetNumber)
     205               0 :                 elog(ERROR, "failed to add index item to \"%s\"",
     206                 :                          RelationGetRelationName(rel));
     207                 : 
     208           40018 :         return itup_off;
     209                 : }

Generated by: LTP GCOV extension version 1.5