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

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * gistscan.c
  4.  *   routines to manage scans on index relations
  5.  *
  6.  *
  7.  * IDENTIFICATION
  8.  *   /usr/local/devel/pglite/cvs/src/backend/access/gist/gistscan.c,v 1.7 1995/06/14 00:10:05 jolly Exp
  9.  *
  10.  *-------------------------------------------------------------------------
  11.  */
  12. #include "postgres.h"
  13. #include "access/genam.h"
  14. #include "access/gist.h"
  15. #include "access/gistscan.h"
  16. /* routines defined and used here */
  17. static void gistregscan(IndexScanDesc s);
  18. static void gistdropscan(IndexScanDesc s);
  19. static void gistadjone(IndexScanDesc s, int op, BlockNumber blkno,
  20.    OffsetNumber offnum);
  21. static void adjuststack(GISTSTACK *stk, BlockNumber blkno,
  22. OffsetNumber offnum);
  23. static void adjustiptr(IndexScanDesc s, ItemPointer iptr,
  24.    int op, BlockNumber blkno, OffsetNumber offnum);
  25. /*
  26.  * Whenever we start a GiST scan in a backend, we register it in private
  27.  * space. Then if the GiST index gets updated, we check all registered
  28.  * scans and adjust them if the tuple they point at got moved by the
  29.  * update.  We only need to do this in private space, because when we update
  30.  * an GiST we have a write lock on the tree, so no other process can have
  31.  * any locks at all on it.  A single transaction can have write and read
  32.  * locks on the same object, so that's why we need to handle this case.
  33.  */
  34. typedef struct GISTScanListData
  35. {
  36. IndexScanDesc gsl_scan;
  37. struct GISTScanListData *gsl_next;
  38. } GISTScanListData;
  39. typedef GISTScanListData *GISTScanList;
  40. /* pointer to list of local scans on GiSTs */
  41. static GISTScanList GISTScans = (GISTScanList) NULL;
  42. IndexScanDesc
  43. gistbeginscan(Relation r,
  44.   bool fromEnd,
  45.   uint16 nkeys,
  46.   ScanKey key)
  47. {
  48. IndexScanDesc s;
  49. /*
  50.  * Let index_beginscan does its work...
  51.  *
  52.  * RelationSetLockForRead(r);
  53.  */
  54. s = RelationGetIndexScan(r, fromEnd, nkeys, key);
  55. gistregscan(s);
  56. return s;
  57. }
  58. void
  59. gistrescan(IndexScanDesc s, bool fromEnd, ScanKey key)
  60. {
  61. GISTScanOpaque p;
  62. int i;
  63. if (!IndexScanIsValid(s))
  64. {
  65. elog(ERROR, "gistrescan: invalid scan.");
  66. return;
  67. }
  68. /*
  69.  * Clear all the pointers.
  70.  */
  71. ItemPointerSetInvalid(&s->previousItemData);
  72. ItemPointerSetInvalid(&s->currentItemData);
  73. ItemPointerSetInvalid(&s->nextItemData);
  74. ItemPointerSetInvalid(&s->previousMarkData);
  75. ItemPointerSetInvalid(&s->currentMarkData);
  76. ItemPointerSetInvalid(&s->nextMarkData);
  77. /*
  78.  * Set flags.
  79.  */
  80. if (RelationGetNumberOfBlocks(s->relation) == 0)
  81. s->flags = ScanUnmarked;
  82. else if (fromEnd)
  83. s->flags = ScanUnmarked | ScanUncheckedPrevious;
  84. else
  85. s->flags = ScanUnmarked | ScanUncheckedNext;
  86. s->scanFromEnd = fromEnd;
  87. if (s->numberOfKeys > 0)
  88. {
  89. memmove(s->keyData,
  90. key,
  91. s->numberOfKeys * sizeof(ScanKeyData));
  92. }
  93. p = (GISTScanOpaque) s->opaque;
  94. if (p != (GISTScanOpaque) NULL)
  95. {
  96. gistfreestack(p->s_stack);
  97. gistfreestack(p->s_markstk);
  98. p->s_stack = p->s_markstk = (GISTSTACK *) NULL;
  99. p->s_flags = 0x0;
  100. for (i = 0; i < s->numberOfKeys; i++)
  101. {
  102. s->keyData[i].sk_procedure
  103. = RelationGetGISTStrategy(s->relation, s->keyData[i].sk_attno,
  104.   s->keyData[i].sk_procedure);
  105. s->keyData[i].sk_func = p->giststate->consistentFn;
  106. }
  107. }
  108. else
  109. {
  110. /* initialize opaque data */
  111. p = (GISTScanOpaque) palloc(sizeof(GISTScanOpaqueData));
  112. p->s_stack = p->s_markstk = (GISTSTACK *) NULL;
  113. p->s_flags = 0x0;
  114. s->opaque = p;
  115. p->giststate = (GISTSTATE *) palloc(sizeof(GISTSTATE));
  116. initGISTstate(p->giststate, s->relation);
  117. if (s->numberOfKeys > 0)
  118. /*
  119.  * * Play games here with the scan key to use the Consistent *
  120.  * function for all comparisons: * 1) the sk_procedure field
  121.  * will now be used to hold the *  strategy number * 2) the
  122.  * sk_func field will point to the Consistent function
  123.  */
  124. for (i = 0; i < s->numberOfKeys; i++)
  125. {
  126. /*
  127.  * s->keyData[i].sk_procedure =
  128.  * index_getprocid(s->relation, 1, GIST_CONSISTENT_PROC);
  129.  */
  130. s->keyData[i].sk_procedure
  131. = RelationGetGISTStrategy(s->relation, s->keyData[i].sk_attno,
  132.   s->keyData[i].sk_procedure);
  133. s->keyData[i].sk_func = p->giststate->consistentFn;
  134. }
  135. }
  136. }
  137. void
  138. gistmarkpos(IndexScanDesc s)
  139. {
  140. GISTScanOpaque p;
  141. GISTSTACK  *o,
  142.    *n,
  143.    *tmp;
  144. s->currentMarkData = s->currentItemData;
  145. p = (GISTScanOpaque) s->opaque;
  146. if (p->s_flags & GS_CURBEFORE)
  147. p->s_flags |= GS_MRKBEFORE;
  148. else
  149. p->s_flags &= ~GS_MRKBEFORE;
  150. o = (GISTSTACK *) NULL;
  151. n = p->s_stack;
  152. /* copy the parent stack from the current item data */
  153. while (n != (GISTSTACK *) NULL)
  154. {
  155. tmp = (GISTSTACK *) palloc(sizeof(GISTSTACK));
  156. tmp->gs_child = n->gs_child;
  157. tmp->gs_blk = n->gs_blk;
  158. tmp->gs_parent = o;
  159. o = tmp;
  160. n = n->gs_parent;
  161. }
  162. gistfreestack(p->s_markstk);
  163. p->s_markstk = o;
  164. }
  165. void
  166. gistrestrpos(IndexScanDesc s)
  167. {
  168. GISTScanOpaque p;
  169. GISTSTACK  *o,
  170.    *n,
  171.    *tmp;
  172. s->currentItemData = s->currentMarkData;
  173. p = (GISTScanOpaque) s->opaque;
  174. if (p->s_flags & GS_MRKBEFORE)
  175. p->s_flags |= GS_CURBEFORE;
  176. else
  177. p->s_flags &= ~GS_CURBEFORE;
  178. o = (GISTSTACK *) NULL;
  179. n = p->s_markstk;
  180. /* copy the parent stack from the current item data */
  181. while (n != (GISTSTACK *) NULL)
  182. {
  183. tmp = (GISTSTACK *) palloc(sizeof(GISTSTACK));
  184. tmp->gs_child = n->gs_child;
  185. tmp->gs_blk = n->gs_blk;
  186. tmp->gs_parent = o;
  187. o = tmp;
  188. n = n->gs_parent;
  189. }
  190. gistfreestack(p->s_stack);
  191. p->s_stack = o;
  192. }
  193. void
  194. gistendscan(IndexScanDesc s)
  195. {
  196. GISTScanOpaque p;
  197. p = (GISTScanOpaque) s->opaque;
  198. if (p != (GISTScanOpaque) NULL)
  199. {
  200. gistfreestack(p->s_stack);
  201. gistfreestack(p->s_markstk);
  202. pfree(s->opaque);
  203. }
  204. gistdropscan(s);
  205. /* XXX don't unset read lock -- two-phase locking */
  206. }
  207. static void
  208. gistregscan(IndexScanDesc s)
  209. {
  210. GISTScanList l;
  211. l = (GISTScanList) palloc(sizeof(GISTScanListData));
  212. l->gsl_scan = s;
  213. l->gsl_next = GISTScans;
  214. GISTScans = l;
  215. }
  216. static void
  217. gistdropscan(IndexScanDesc s)
  218. {
  219. GISTScanList l;
  220. GISTScanList prev;
  221. prev = (GISTScanList) NULL;
  222. for (l = GISTScans;
  223.  l != (GISTScanList) NULL && l->gsl_scan != s;
  224.  l = l->gsl_next)
  225. prev = l;
  226. if (l == (GISTScanList) NULL)
  227. elog(ERROR, "GiST scan list corrupted -- cannot find 0x%lx", s);
  228. if (prev == (GISTScanList) NULL)
  229. GISTScans = l->gsl_next;
  230. else
  231. prev->gsl_next = l->gsl_next;
  232. pfree(l);
  233. }
  234. void
  235. gistadjscans(Relation rel, int op, BlockNumber blkno, OffsetNumber offnum)
  236. {
  237. GISTScanList l;
  238. Oid relid;
  239. relid = RelationGetRelid(rel);
  240. for (l = GISTScans; l != (GISTScanList) NULL; l = l->gsl_next)
  241. {
  242. if (l->gsl_scan->relation->rd_id == relid)
  243. gistadjone(l->gsl_scan, op, blkno, offnum);
  244. }
  245. }
  246. /*
  247.  * gistadjone() -- adjust one scan for update.
  248.  *
  249.  * By here, the scan passed in is on a modified relation. Op tells
  250.  * us what the modification is, and blkno and offind tell us what
  251.  * block and offset index were affected.  This routine checks the
  252.  * current and marked positions, and the current and marked stacks,
  253.  * to see if any stored location needs to be changed because of the
  254.  * update.  If so, we make the change here.
  255.  */
  256. static void
  257. gistadjone(IndexScanDesc s,
  258.    int op,
  259.    BlockNumber blkno,
  260.    OffsetNumber offnum)
  261. {
  262. GISTScanOpaque so;
  263. adjustiptr(s, &(s->currentItemData), op, blkno, offnum);
  264. adjustiptr(s, &(s->currentMarkData), op, blkno, offnum);
  265. so = (GISTScanOpaque) s->opaque;
  266. if (op == GISTOP_SPLIT)
  267. {
  268. adjuststack(so->s_stack, blkno, offnum);
  269. adjuststack(so->s_markstk, blkno, offnum);
  270. }
  271. }
  272. /*
  273.  * adjustiptr() -- adjust current and marked item pointers in the scan
  274.  *
  275.  * Depending on the type of update and the place it happened, we
  276.  * need to do nothing, to back up one record, or to start over on
  277.  * the same page.
  278.  */
  279. static void
  280. adjustiptr(IndexScanDesc s,
  281.    ItemPointer iptr,
  282.    int op,
  283.    BlockNumber blkno,
  284.    OffsetNumber offnum)
  285. {
  286. OffsetNumber curoff;
  287. GISTScanOpaque so;
  288. if (ItemPointerIsValid(iptr))
  289. {
  290. if (ItemPointerGetBlockNumber(iptr) == blkno)
  291. {
  292. curoff = ItemPointerGetOffsetNumber(iptr);
  293. so = (GISTScanOpaque) s->opaque;
  294. switch (op)
  295. {
  296. case GISTOP_DEL:
  297. /* back up one if we need to */
  298. if (curoff >= offnum)
  299. {
  300. if (curoff > FirstOffsetNumber)
  301. {
  302. /* just adjust the item pointer */
  303. ItemPointerSet(iptr, blkno, OffsetNumberPrev(curoff));
  304. }
  305. else
  306. {
  307. /*
  308.  * remember that we're before the current
  309.  * tuple
  310.  */
  311. ItemPointerSet(iptr, blkno, FirstOffsetNumber);
  312. if (iptr == &(s->currentItemData))
  313. so->s_flags |= GS_CURBEFORE;
  314. else
  315. so->s_flags |= GS_MRKBEFORE;
  316. }
  317. }
  318. break;
  319. case GISTOP_SPLIT:
  320. /* back to start of page on split */
  321. ItemPointerSet(iptr, blkno, FirstOffsetNumber);
  322. if (iptr == &(s->currentItemData))
  323. so->s_flags &= ~GS_CURBEFORE;
  324. else
  325. so->s_flags &= ~GS_MRKBEFORE;
  326. break;
  327. default:
  328. elog(ERROR, "Bad operation in GiST scan adjust: %d", op);
  329. }
  330. }
  331. }
  332. }
  333. /*
  334.  * adjuststack() -- adjust the supplied stack for a split on a page in
  335.  *  the index we're scanning.
  336.  *
  337.  * If a page on our parent stack has split, we need to back up to the
  338.  * beginning of the page and rescan it.  The reason for this is that
  339.  * the split algorithm for GiSTs doesn't order tuples in any useful
  340.  * way on a single page.  This means on that a split, we may wind up
  341.  * looking at some heap tuples more than once.  This is handled in the
  342.  * access method update code for heaps; if we've modified the tuple we
  343.  * are looking at already in this transaction, we ignore the update
  344.  * request.
  345.  */
  346. /*ARGSUSED*/
  347. static void
  348. adjuststack(GISTSTACK *stk,
  349. BlockNumber blkno,
  350. OffsetNumber offnum)
  351. {
  352. while (stk != (GISTSTACK *) NULL)
  353. {
  354. if (stk->gs_blk == blkno)
  355. stk->gs_child = FirstOffsetNumber;
  356. stk = stk->gs_parent;
  357. }
  358. }