hashinsert.c
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:6k
源码类别:

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * hashinsert.c
  4.  *   Item insertion in hash tables for Postgres.
  5.  *
  6.  * Copyright (c) 1994, Regents of the University of California
  7.  *
  8.  *
  9.  * IDENTIFICATION
  10.  *   $Header: /usr/local/cvsroot/pgsql/src/backend/access/hash/hashinsert.c,v 1.15.2.1 1999/08/02 05:24:33 scrappy Exp $
  11.  *
  12.  *-------------------------------------------------------------------------
  13.  */
  14. #include "postgres.h"
  15. #include "access/hash.h"
  16. static InsertIndexResult _hash_insertonpg(Relation rel, Buffer buf, int keysz, ScanKey scankey, HashItem hitem, Buffer metabuf);
  17. static OffsetNumber _hash_pgaddtup(Relation rel, Buffer buf, int keysz, ScanKey itup_scankey, Size itemsize, HashItem hitem);
  18. /*
  19.  * _hash_doinsert() -- Handle insertion of a single HashItem in the table.
  20.  *
  21.  * This routine is called by the public interface routines, hashbuild
  22.  * and hashinsert.  By here, hashitem is filled in, and has a unique
  23.  * (xid, seqno) pair. The datum to be used as a "key" is in the
  24.  * hashitem.
  25.  */
  26. InsertIndexResult
  27. _hash_doinsert(Relation rel, HashItem hitem)
  28. {
  29. Buffer buf;
  30. Buffer metabuf;
  31. BlockNumber blkno;
  32. HashMetaPage metap;
  33. IndexTuple itup;
  34. InsertIndexResult res;
  35. ScanKey itup_scankey;
  36. int natts;
  37. Page page;
  38. metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ);
  39. metap = (HashMetaPage) BufferGetPage(metabuf);
  40. _hash_checkpage((Page) metap, LH_META_PAGE);
  41. /* we need a scan key to do our search, so build one */
  42. itup = &(hitem->hash_itup);
  43. if ((natts = rel->rd_rel->relnatts) != 1)
  44. elog(ERROR, "Hash indices valid for only one index key.");
  45. itup_scankey = _hash_mkscankey(rel, itup, metap);
  46. /*
  47.  * find the first page in the bucket chain containing this key and
  48.  * place it in buf.  _hash_search obtains a read lock for us.
  49.  */
  50. _hash_search(rel, natts, itup_scankey, &buf, metap);
  51. page = BufferGetPage(buf);
  52. _hash_checkpage(page, LH_BUCKET_PAGE);
  53. /*
  54.  * trade in our read lock for a write lock so that we can do the
  55.  * insertion.
  56.  */
  57. blkno = BufferGetBlockNumber(buf);
  58. _hash_relbuf(rel, buf, HASH_READ);
  59. buf = _hash_getbuf(rel, blkno, HASH_WRITE);
  60. /*
  61.  * XXX btree comment (haven't decided what to do in hash): don't think
  62.  * the bucket can be split while we're reading the metapage.
  63.  *
  64.  * If the page was split between the time that we surrendered our read
  65.  * lock and acquired our write lock, then this page may no longer be
  66.  * the right place for the key we want to insert.
  67.  */
  68. /* do the insertion */
  69. res = _hash_insertonpg(rel, buf, natts, itup_scankey,
  70.    hitem, metabuf);
  71. /* be tidy */
  72. _hash_freeskey(itup_scankey);
  73. return res;
  74. }
  75. /*
  76.  * _hash_insertonpg() -- Insert a tuple on a particular page in the table.
  77.  *
  78.  * This recursive procedure does the following things:
  79.  *
  80.  * +  if necessary, splits the target page.
  81.  * +  inserts the tuple.
  82.  *
  83.  * On entry, we must have the right buffer on which to do the
  84.  * insertion, and the buffer must be pinned and locked.  On return,
  85.  * we will have dropped both the pin and the write lock on the buffer.
  86.  *
  87.  */
  88. static InsertIndexResult
  89. _hash_insertonpg(Relation rel,
  90.  Buffer buf,
  91.  int keysz,
  92.  ScanKey scankey,
  93.  HashItem hitem,
  94.  Buffer metabuf)
  95. {
  96. InsertIndexResult res;
  97. Page page;
  98. BlockNumber itup_blkno;
  99. OffsetNumber itup_off;
  100. int itemsz;
  101. HashPageOpaque pageopaque;
  102. bool do_expand = false;
  103. Buffer ovflbuf;
  104. HashMetaPage metap;
  105. Bucket bucket;
  106. metap = (HashMetaPage) BufferGetPage(metabuf);
  107. _hash_checkpage((Page) metap, LH_META_PAGE);
  108. page = BufferGetPage(buf);
  109. _hash_checkpage(page, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
  110. pageopaque = (HashPageOpaque) PageGetSpecialPointer(page);
  111. bucket = pageopaque->hasho_bucket;
  112. itemsz = IndexTupleDSize(hitem->hash_itup)
  113. + (sizeof(HashItemData) - sizeof(IndexTupleData));
  114. itemsz = MAXALIGN(itemsz);
  115. while (PageGetFreeSpace(page) < itemsz)
  116. {
  117. /*
  118.  * no space on this page; check for an overflow page
  119.  */
  120. if (BlockNumberIsValid(pageopaque->hasho_nextblkno))
  121. {
  122. /*
  123.  * ovfl page exists; go get it.  if it doesn't have room,
  124.  * we'll find out next pass through the loop test above.
  125.  */
  126. ovflbuf = _hash_getbuf(rel, pageopaque->hasho_nextblkno,
  127.    HASH_WRITE);
  128. _hash_relbuf(rel, buf, HASH_WRITE);
  129. buf = ovflbuf;
  130. page = BufferGetPage(buf);
  131. }
  132. else
  133. {
  134. /*
  135.  * we're at the end of the bucket chain and we haven't found a
  136.  * page with enough room.  allocate a new overflow page.
  137.  */
  138. do_expand = true;
  139. ovflbuf = _hash_addovflpage(rel, &metabuf, buf);
  140. _hash_relbuf(rel, buf, HASH_WRITE);
  141. buf = ovflbuf;
  142. page = BufferGetPage(buf);
  143. if (PageGetFreeSpace(page) < itemsz)
  144. {
  145. /* it doesn't fit on an empty page -- give up */
  146. elog(ERROR, "hash item too large");
  147. }
  148. }
  149. _hash_checkpage(page, LH_OVERFLOW_PAGE);
  150. pageopaque = (HashPageOpaque) PageGetSpecialPointer(page);
  151. Assert(pageopaque->hasho_bucket == bucket);
  152. }
  153. itup_off = _hash_pgaddtup(rel, buf, keysz, scankey, itemsz, hitem);
  154. itup_blkno = BufferGetBlockNumber(buf);
  155. /* by here, the new tuple is inserted */
  156. res = (InsertIndexResult) palloc(sizeof(InsertIndexResultData));
  157. ItemPointerSet(&(res->pointerData), itup_blkno, itup_off);
  158. if (res != NULL)
  159. {
  160. /*
  161.  * Increment the number of keys in the table. We switch lock
  162.  * access type just for a moment to allow greater accessibility to
  163.  * the metapage.
  164.  */
  165. metap = (HashMetaPage) _hash_chgbufaccess(rel, &metabuf,
  166.   HASH_READ, HASH_WRITE);
  167. metap->hashm_nkeys += 1;
  168. metap = (HashMetaPage) _hash_chgbufaccess(rel, &metabuf,
  169.   HASH_WRITE, HASH_READ);
  170. }
  171. _hash_wrtbuf(rel, buf);
  172. if (do_expand ||
  173. (metap->hashm_nkeys / (metap->hashm_maxbucket + 1))
  174. > metap->hashm_ffactor)
  175. _hash_expandtable(rel, metabuf);
  176. _hash_relbuf(rel, metabuf, HASH_READ);
  177. return res;
  178. }
  179. /*
  180.  * _hash_pgaddtup() -- add a tuple to a particular page in the index.
  181.  *
  182.  * This routine adds the tuple to the page as requested, and keeps the
  183.  * write lock and reference associated with the page's buffer.  It is
  184.  * an error to call pgaddtup() without a write lock and reference.
  185.  */
  186. static OffsetNumber
  187. _hash_pgaddtup(Relation rel,
  188.    Buffer buf,
  189.    int keysz,
  190.    ScanKey itup_scankey,
  191.    Size itemsize,
  192.    HashItem hitem)
  193. {
  194. OffsetNumber itup_off;
  195. Page page;
  196. page = BufferGetPage(buf);
  197. _hash_checkpage(page, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
  198. itup_off = OffsetNumberNext(PageGetMaxOffsetNumber(page));
  199. PageAddItem(page, (Item) hitem, itemsize, itup_off, LP_USED);
  200. /* write the buffer, but hold our lock */
  201. _hash_wrtnorelbuf(rel, buf);
  202. return itup_off;
  203. }