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

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * rtscan.c
  4.  *   routines to manage scans on index relations
  5.  *
  6.  * Copyright (c) 1994, Regents of the University of California
  7.  *
  8.  *
  9.  * IDENTIFICATION
  10.  *   $Header: /usr/local/cvsroot/pgsql/src/backend/access/rtree/rtscan.c,v 1.23.2.1 1999/08/02 05:24:44 scrappy Exp $
  11.  *
  12.  *-------------------------------------------------------------------------
  13.  */
  14. #include "postgres.h"
  15. #include "access/genam.h"
  16. #include "access/rtree.h"
  17. /* routines defined and used here */
  18. static void rtregscan(IndexScanDesc s);
  19. static void rtdropscan(IndexScanDesc s);
  20. static void rtadjone(IndexScanDesc s, int op, BlockNumber blkno,
  21.  OffsetNumber offnum);
  22. static void adjuststack(RTSTACK *stk, BlockNumber blkno,
  23. OffsetNumber offnum);
  24. static void adjustiptr(IndexScanDesc s, ItemPointer iptr,
  25.    int op, BlockNumber blkno, OffsetNumber offnum);
  26. /*
  27.  * Whenever we start an rtree scan in a backend, we register it in private
  28.  * space. Then if the rtree index gets updated, we check all registered
  29.  * scans and adjust them if the tuple they point at got moved by the
  30.  * update.  We only need to do this in private space, because when we update
  31.  * an rtree we have a write lock on the tree, so no other process can have
  32.  * any locks at all on it.  A single transaction can have write and read
  33.  * locks on the same object, so that's why we need to handle this case.
  34.  */
  35. typedef struct RTScanListData
  36. {
  37. IndexScanDesc rtsl_scan;
  38. struct RTScanListData *rtsl_next;
  39. } RTScanListData;
  40. typedef RTScanListData *RTScanList;
  41. /* pointer to list of local scans on rtrees */
  42. static RTScanList RTScans = (RTScanList) NULL;
  43. IndexScanDesc
  44. rtbeginscan(Relation r,
  45. bool fromEnd,
  46. uint16 nkeys,
  47. ScanKey key)
  48. {
  49. IndexScanDesc s;
  50. /*
  51.  * Let index_beginscan does its work...
  52.  *
  53.  * RelationSetLockForRead(r);
  54.  */
  55. s = RelationGetIndexScan(r, fromEnd, nkeys, key);
  56. rtregscan(s);
  57. return s;
  58. }
  59. void
  60. rtrescan(IndexScanDesc s, bool fromEnd, ScanKey key)
  61. {
  62. RTreeScanOpaque p;
  63. RegProcedure internal_proc;
  64. int i;
  65. if (!IndexScanIsValid(s))
  66. {
  67. elog(ERROR, "rtrescan: invalid scan.");
  68. return;
  69. }
  70. /*
  71.  * Clear all the pointers.
  72.  */
  73. ItemPointerSetInvalid(&s->previousItemData);
  74. ItemPointerSetInvalid(&s->currentItemData);
  75. ItemPointerSetInvalid(&s->nextItemData);
  76. ItemPointerSetInvalid(&s->previousMarkData);
  77. ItemPointerSetInvalid(&s->currentMarkData);
  78. ItemPointerSetInvalid(&s->nextMarkData);
  79. /*
  80.  * Set flags.
  81.  */
  82. if (RelationGetNumberOfBlocks(s->relation) == 0)
  83. s->flags = ScanUnmarked;
  84. else if (fromEnd)
  85. s->flags = ScanUnmarked | ScanUncheckedPrevious;
  86. else
  87. s->flags = ScanUnmarked | ScanUncheckedNext;
  88. s->scanFromEnd = fromEnd;
  89. if (s->numberOfKeys > 0)
  90. {
  91. memmove(s->keyData,
  92. key,
  93. s->numberOfKeys * sizeof(ScanKeyData));
  94. }
  95. p = (RTreeScanOpaque) s->opaque;
  96. if (p != (RTreeScanOpaque) NULL)
  97. {
  98. freestack(p->s_stack);
  99. freestack(p->s_markstk);
  100. p->s_stack = p->s_markstk = (RTSTACK *) NULL;
  101. p->s_flags = 0x0;
  102. for (i = 0; i < s->numberOfKeys; i++)
  103. p->s_internalKey[i].sk_argument = s->keyData[i].sk_argument;
  104. }
  105. else
  106. {
  107. /* initialize opaque data */
  108. p = (RTreeScanOpaque) palloc(sizeof(RTreeScanOpaqueData));
  109. p->s_stack = p->s_markstk = (RTSTACK *) NULL;
  110. p->s_internalNKey = s->numberOfKeys;
  111. p->s_flags = 0x0;
  112. s->opaque = p;
  113. if (s->numberOfKeys > 0)
  114. {
  115. p->s_internalKey = (ScanKey) palloc(sizeof(ScanKeyData) * s->numberOfKeys);
  116. /*
  117.  * Scans on internal pages use different operators than they
  118.  * do on leaf pages.  For example, if the user wants all boxes
  119.  * that exactly match (x1,y1,x2,y2), then on internal pages we
  120.  * need to find all boxes that contain (x1,y1,x2,y2).
  121.  */
  122. for (i = 0; i < s->numberOfKeys; i++)
  123. {
  124. p->s_internalKey[i].sk_argument = s->keyData[i].sk_argument;
  125. internal_proc = RTMapOperator(s->relation,
  126.   s->keyData[i].sk_attno,
  127.   s->keyData[i].sk_procedure);
  128. ScanKeyEntryInitialize(&(p->s_internalKey[i]),
  129.    s->keyData[i].sk_flags,
  130.    s->keyData[i].sk_attno,
  131.    internal_proc,
  132.    s->keyData[i].sk_argument);
  133. }
  134. }
  135. }
  136. }
  137. void
  138. rtmarkpos(IndexScanDesc s)
  139. {
  140. RTreeScanOpaque p;
  141. RTSTACK    *o,
  142.    *n,
  143.    *tmp;
  144. s->currentMarkData = s->currentItemData;
  145. p = (RTreeScanOpaque) s->opaque;
  146. if (p->s_flags & RTS_CURBEFORE)
  147. p->s_flags |= RTS_MRKBEFORE;
  148. else
  149. p->s_flags &= ~RTS_MRKBEFORE;
  150. o = (RTSTACK *) NULL;
  151. n = p->s_stack;
  152. /* copy the parent stack from the current item data */
  153. while (n != (RTSTACK *) NULL)
  154. {
  155. tmp = (RTSTACK *) palloc(sizeof(RTSTACK));
  156. tmp->rts_child = n->rts_child;
  157. tmp->rts_blk = n->rts_blk;
  158. tmp->rts_parent = o;
  159. o = tmp;
  160. n = n->rts_parent;
  161. }
  162. freestack(p->s_markstk);
  163. p->s_markstk = o;
  164. }
  165. void
  166. rtrestrpos(IndexScanDesc s)
  167. {
  168. RTreeScanOpaque p;
  169. RTSTACK    *o,
  170.    *n,
  171.    *tmp;
  172. s->currentItemData = s->currentMarkData;
  173. p = (RTreeScanOpaque) s->opaque;
  174. if (p->s_flags & RTS_MRKBEFORE)
  175. p->s_flags |= RTS_CURBEFORE;
  176. else
  177. p->s_flags &= ~RTS_CURBEFORE;
  178. o = (RTSTACK *) NULL;
  179. n = p->s_markstk;
  180. /* copy the parent stack from the current item data */
  181. while (n != (RTSTACK *) NULL)
  182. {
  183. tmp = (RTSTACK *) palloc(sizeof(RTSTACK));
  184. tmp->rts_child = n->rts_child;
  185. tmp->rts_blk = n->rts_blk;
  186. tmp->rts_parent = o;
  187. o = tmp;
  188. n = n->rts_parent;
  189. }
  190. freestack(p->s_stack);
  191. p->s_stack = o;
  192. }
  193. void
  194. rtendscan(IndexScanDesc s)
  195. {
  196. RTreeScanOpaque p;
  197. p = (RTreeScanOpaque) s->opaque;
  198. if (p != (RTreeScanOpaque) NULL)
  199. {
  200. freestack(p->s_stack);
  201. freestack(p->s_markstk);
  202. pfree(s->opaque);
  203. }
  204. rtdropscan(s);
  205. /* XXX don't unset read lock -- two-phase locking */
  206. }
  207. static void
  208. rtregscan(IndexScanDesc s)
  209. {
  210. RTScanList l;
  211. l = (RTScanList) palloc(sizeof(RTScanListData));
  212. l->rtsl_scan = s;
  213. l->rtsl_next = RTScans;
  214. RTScans = l;
  215. }
  216. static void
  217. rtdropscan(IndexScanDesc s)
  218. {
  219. RTScanList l;
  220. RTScanList prev;
  221. prev = (RTScanList) NULL;
  222. for (l = RTScans;
  223.  l != (RTScanList) NULL && l->rtsl_scan != s;
  224.  l = l->rtsl_next)
  225. prev = l;
  226. if (l == (RTScanList) NULL)
  227. elog(ERROR, "rtree scan list corrupted -- cannot find 0x%lx", s);
  228. if (prev == (RTScanList) NULL)
  229. RTScans = l->rtsl_next;
  230. else
  231. prev->rtsl_next = l->rtsl_next;
  232. pfree(l);
  233. }
  234. void
  235. rtadjscans(Relation r, int op, BlockNumber blkno, OffsetNumber offnum)
  236. {
  237. RTScanList l;
  238. Oid relid;
  239. relid = RelationGetRelid(r);
  240. for (l = RTScans; l != (RTScanList) NULL; l = l->rtsl_next)
  241. {
  242. if (RelationGetRelid(l->rtsl_scan->relation) == relid)
  243. rtadjone(l->rtsl_scan, op, blkno, offnum);
  244. }
  245. }
  246. /*
  247.  * rtadjone() -- 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. rtadjone(IndexScanDesc s,
  258.  int op,
  259.  BlockNumber blkno,
  260.  OffsetNumber offnum)
  261. {
  262. RTreeScanOpaque so;
  263. adjustiptr(s, &(s->currentItemData), op, blkno, offnum);
  264. adjustiptr(s, &(s->currentMarkData), op, blkno, offnum);
  265. so = (RTreeScanOpaque) s->opaque;
  266. if (op == RTOP_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. RTreeScanOpaque so;
  288. if (ItemPointerIsValid(iptr))
  289. {
  290. if (ItemPointerGetBlockNumber(iptr) == blkno)
  291. {
  292. curoff = ItemPointerGetOffsetNumber(iptr);
  293. so = (RTreeScanOpaque) s->opaque;
  294. switch (op)
  295. {
  296. case RTOP_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 |= RTS_CURBEFORE;
  314. else
  315. so->s_flags |= RTS_MRKBEFORE;
  316. }
  317. }
  318. break;
  319. case RTOP_SPLIT:
  320. /* back to start of page on split */
  321. ItemPointerSet(iptr, blkno, FirstOffsetNumber);
  322. if (iptr == &(s->currentItemData))
  323. so->s_flags &= ~RTS_CURBEFORE;
  324. else
  325. so->s_flags &= ~RTS_MRKBEFORE;
  326. break;
  327. default:
  328. elog(ERROR, "Bad operation in rtree 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 rtrees 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(RTSTACK *stk,
  349. BlockNumber blkno,
  350. OffsetNumber offnum)
  351. {
  352. while (stk != (RTSTACK *) NULL)
  353. {
  354. if (stk->rts_blk == blkno)
  355. stk->rts_child = FirstOffsetNumber;
  356. stk = stk->rts_parent;
  357. }
  358. }