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

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * bufpage.c
  4.  *   POSTGRES standard buffer page code.
  5.  *
  6.  * Copyright (c) 1994, Regents of the University of California
  7.  *
  8.  *
  9.  * IDENTIFICATION
  10.  *   $Header: /usr/local/cvsroot/pgsql/src/backend/storage/page/bufpage.c,v 1.23 1999/07/03 00:32:48 momjian Exp $
  11.  *
  12.  *-------------------------------------------------------------------------
  13.  */
  14. #include <string.h>
  15. #include <sys/types.h>
  16. #include <sys/file.h>
  17. #include "postgres.h"
  18. #include "storage/item.h"
  19. #include "storage/buf.h"
  20. #include "storage/bufmgr.h"
  21. #include "utils/palloc.h"
  22. #include "utils/memutils.h"
  23. #include "storage/bufpage.h"
  24. static void PageIndexTupleDeleteAdjustLinePointers(PageHeader phdr,
  25.    char *location, Size size);
  26. static bool PageManagerShuffle = true; /* default is shuffle mode */
  27. /* ----------------------------------------------------------------
  28.  * Page support functions
  29.  * ----------------------------------------------------------------
  30.  */
  31. /*
  32.  * PageInit
  33.  * Initializes the contents of a page.
  34.  */
  35. void
  36. PageInit(Page page, Size pageSize, Size specialSize)
  37. {
  38. PageHeader p = (PageHeader) page;
  39. Assert(pageSize == BLCKSZ);
  40. Assert(pageSize >
  41.  specialSize + sizeof(PageHeaderData) - sizeof(ItemIdData));
  42. specialSize = DOUBLEALIGN(specialSize);
  43. p->pd_lower = sizeof(PageHeaderData) - sizeof(ItemIdData);
  44. p->pd_upper = pageSize - specialSize;
  45. p->pd_special = pageSize - specialSize;
  46. PageSetPageSize(page, pageSize);
  47. }
  48. /*
  49.  * PageAddItem
  50.  * Adds item to the given page.
  51.  *
  52.  * Note:
  53.  * This does not assume that the item resides on a single page.
  54.  * It is the responsiblity of the caller to act appropriately
  55.  * depending on this fact.  The "pskip" routines provide a
  56.  * friendlier interface, in this case.
  57.  *
  58.  * This does change the status of any of the resources passed.
  59.  * The semantics may change in the future.
  60.  *
  61.  * This routine should probably be combined with others?
  62.  */
  63. /* ----------------
  64.  * PageAddItem
  65.  *
  66.  * add an item to a page.
  67.  *
  68.  *  Notes on interface:
  69.  * If offsetNumber is valid, shuffle ItemId's down to make room
  70.  * to use it, if PageManagerShuffle is true.  If PageManagerShuffle is
  71.  * false, then overwrite the specified ItemId.  (PageManagerShuffle is
  72.  * true by default, and is modified by calling PageManagerModeSet.)
  73.  * If offsetNumber is not valid, then assign one by finding the first
  74.  * one that is both unused and deallocated.
  75.  *
  76.  *  NOTE: If offsetNumber is valid, and PageManagerShuffle is true, it
  77.  * is assumed that there is room on the page to shuffle the ItemId's
  78.  * down by one.
  79.  * ----------------
  80.  */
  81. OffsetNumber
  82. PageAddItem(Page page,
  83. Item item,
  84. Size size,
  85. OffsetNumber offsetNumber,
  86. ItemIdFlags flags)
  87. {
  88. int i;
  89. Size alignedSize;
  90. Offset lower;
  91. Offset upper;
  92. ItemId itemId;
  93. ItemId fromitemId,
  94. toitemId;
  95. OffsetNumber limit;
  96. bool shuffled = false;
  97. /*
  98.  * Find first unallocated offsetNumber
  99.  */
  100. limit = OffsetNumberNext(PageGetMaxOffsetNumber(page));
  101. /* was offsetNumber passed in? */
  102. if (OffsetNumberIsValid(offsetNumber))
  103. {
  104. if (PageManagerShuffle == true)
  105. {
  106. /* shuffle ItemId's (Do the PageManager Shuffle...) */
  107. for (i = (limit - 1); i >= offsetNumber; i--)
  108. {
  109. fromitemId = &((PageHeader) page)->pd_linp[i - 1];
  110. toitemId = &((PageHeader) page)->pd_linp[i];
  111. *toitemId = *fromitemId;
  112. }
  113. shuffled = true; /* need to increase "lower" */
  114. }
  115. else
  116. { /* overwrite mode */
  117. itemId = &((PageHeader) page)->pd_linp[offsetNumber - 1];
  118. if (((*itemId).lp_flags & LP_USED) ||
  119. ((*itemId).lp_len != 0))
  120. {
  121. elog(ERROR, "PageAddItem: tried overwrite of used ItemId");
  122. return InvalidOffsetNumber;
  123. }
  124. }
  125. }
  126. else
  127. { /* offsetNumber was not passed in, so find
  128.  * one */
  129. /* look for "recyclable" (unused & deallocated) ItemId */
  130. for (offsetNumber = 1; offsetNumber < limit; offsetNumber++)
  131. {
  132. itemId = &((PageHeader) page)->pd_linp[offsetNumber - 1];
  133. if ((((*itemId).lp_flags & LP_USED) == 0) &&
  134. ((*itemId).lp_len == 0))
  135. break;
  136. }
  137. }
  138. if (offsetNumber > limit)
  139. lower = (Offset) (((char *) (&((PageHeader) page)->pd_linp[offsetNumber])) - ((char *) page));
  140. else if (offsetNumber == limit || shuffled == true)
  141. lower = ((PageHeader) page)->pd_lower + sizeof(ItemIdData);
  142. else
  143. lower = ((PageHeader) page)->pd_lower;
  144. alignedSize = DOUBLEALIGN(size);
  145. upper = ((PageHeader) page)->pd_upper - alignedSize;
  146. if (lower > upper)
  147. return InvalidOffsetNumber;
  148. itemId = &((PageHeader) page)->pd_linp[offsetNumber - 1];
  149. (*itemId).lp_off = upper;
  150. (*itemId).lp_len = size;
  151. (*itemId).lp_flags = flags;
  152. memmove((char *) page + upper, item, size);
  153. ((PageHeader) page)->pd_lower = lower;
  154. ((PageHeader) page)->pd_upper = upper;
  155. return offsetNumber;
  156. }
  157. /*
  158.  * PageGetTempPage
  159.  * Get a temporary page in local memory for special processing
  160.  */
  161. Page
  162. PageGetTempPage(Page page, Size specialSize)
  163. {
  164. Size pageSize;
  165. Size size;
  166. Page temp;
  167. PageHeader thdr;
  168. pageSize = PageGetPageSize(page);
  169. if ((temp = (Page) palloc(pageSize)) == (Page) NULL)
  170. elog(FATAL, "Cannot allocate %d bytes for temp page.", pageSize);
  171. thdr = (PageHeader) temp;
  172. /* copy old page in */
  173. memmove(temp, page, pageSize);
  174. /* clear out the middle */
  175. size = (pageSize - sizeof(PageHeaderData)) + sizeof(ItemIdData);
  176. size -= DOUBLEALIGN(specialSize);
  177. MemSet((char *) &(thdr->pd_linp[0]), 0, size);
  178. /* set high, low water marks */
  179. thdr->pd_lower = sizeof(PageHeaderData) - sizeof(ItemIdData);
  180. thdr->pd_upper = pageSize - DOUBLEALIGN(specialSize);
  181. return temp;
  182. }
  183. /*
  184.  * PageRestoreTempPage
  185.  * Copy temporary page back to permanent page after special processing
  186.  * and release the temporary page.
  187.  */
  188. void
  189. PageRestoreTempPage(Page tempPage, Page oldPage)
  190. {
  191. Size pageSize;
  192. pageSize = PageGetPageSize(tempPage);
  193. memmove((char *) oldPage, (char *) tempPage, pageSize);
  194. pfree(tempPage);
  195. }
  196. /* ----------------
  197.  * itemid stuff for PageRepairFragmentation
  198.  * ----------------
  199.  */
  200. struct itemIdSortData
  201. {
  202. int offsetindex; /* linp array index */
  203. ItemIdData itemiddata;
  204. };
  205. static int
  206. itemidcompare(const void *itemidp1, const void *itemidp2)
  207. {
  208. if (((struct itemIdSortData *) itemidp1)->itemiddata.lp_off ==
  209. ((struct itemIdSortData *) itemidp2)->itemiddata.lp_off)
  210. return 0;
  211. else if (((struct itemIdSortData *) itemidp1)->itemiddata.lp_off <
  212.  ((struct itemIdSortData *) itemidp2)->itemiddata.lp_off)
  213. return 1;
  214. else
  215. return -1;
  216. }
  217. /*
  218.  * PageRepairFragmentation
  219.  * Frees fragmented space on a page.
  220.  */
  221. void
  222. PageRepairFragmentation(Page page)
  223. {
  224. int i;
  225. struct itemIdSortData *itemidbase,
  226.    *itemidptr;
  227. ItemId lp;
  228. int nline,
  229. nused;
  230. Offset upper;
  231. Size alignedSize;
  232. nline = (int16) PageGetMaxOffsetNumber(page);
  233. nused = 0;
  234. for (i = 0; i < nline; i++)
  235. {
  236. lp = ((PageHeader) page)->pd_linp + i;
  237. if ((*lp).lp_flags & LP_USED)
  238. nused++;
  239. }
  240. if (nused == 0)
  241. {
  242. for (i = 0; i < nline; i++)
  243. {
  244. lp = ((PageHeader) page)->pd_linp + i;
  245. if ((*lp).lp_len > 0) /* unused, but allocated */
  246. (*lp).lp_len = 0; /* indicate unused & deallocated */
  247. }
  248. ((PageHeader) page)->pd_upper = ((PageHeader) page)->pd_special;
  249. }
  250. else
  251. { /* nused != 0 */
  252. itemidbase = (struct itemIdSortData *)
  253. palloc(sizeof(struct itemIdSortData) * nused);
  254. MemSet((char *) itemidbase, 0, sizeof(struct itemIdSortData) * nused);
  255. itemidptr = itemidbase;
  256. for (i = 0; i < nline; i++)
  257. {
  258. lp = ((PageHeader) page)->pd_linp + i;
  259. if ((*lp).lp_flags & LP_USED)
  260. {
  261. itemidptr->offsetindex = i;
  262. itemidptr->itemiddata = *lp;
  263. itemidptr++;
  264. }
  265. else
  266. {
  267. if ((*lp).lp_len > 0) /* unused, but allocated */
  268. (*lp).lp_len = 0; /* indicate unused & deallocated */
  269. }
  270. }
  271. /* sort itemIdSortData array... */
  272. qsort((char *) itemidbase, nused, sizeof(struct itemIdSortData),
  273.   itemidcompare);
  274. /* compactify page */
  275. ((PageHeader) page)->pd_upper = ((PageHeader) page)->pd_special;
  276. for (i = 0, itemidptr = itemidbase; i < nused; i++, itemidptr++)
  277. {
  278. lp = ((PageHeader) page)->pd_linp + itemidptr->offsetindex;
  279. alignedSize = DOUBLEALIGN((*lp).lp_len);
  280. upper = ((PageHeader) page)->pd_upper - alignedSize;
  281. memmove((char *) page + upper,
  282. (char *) page + (*lp).lp_off,
  283. (*lp).lp_len);
  284. (*lp).lp_off = upper;
  285. ((PageHeader) page)->pd_upper = upper;
  286. }
  287. pfree(itemidbase);
  288. }
  289. }
  290. /*
  291.  * PageGetFreeSpace
  292.  * Returns the size of the free (allocatable) space on a page.
  293.  */
  294. Size
  295. PageGetFreeSpace(Page page)
  296. {
  297. Size space;
  298. space = ((PageHeader) page)->pd_upper - ((PageHeader) page)->pd_lower;
  299. if (space < sizeof(ItemIdData))
  300. return 0;
  301. space -= sizeof(ItemIdData);/* XXX not always true */
  302. return space;
  303. }
  304. /*
  305.  * PageManagerModeSet
  306.  *
  307.  *  Sets mode to either: ShufflePageManagerMode (the default) or
  308.  *  OverwritePageManagerMode. For use by access methods code
  309.  *  for determining semantics of PageAddItem when the offsetNumber
  310.  *  argument is passed in.
  311.  */
  312. void
  313. PageManagerModeSet(PageManagerMode mode)
  314. {
  315. if (mode == ShufflePageManagerMode)
  316. PageManagerShuffle = true;
  317. else if (mode == OverwritePageManagerMode)
  318. PageManagerShuffle = false;
  319. }
  320. /*
  321.  *----------------------------------------------------------------
  322.  * PageIndexTupleDelete
  323.  *----------------------------------------------------------------
  324.  *
  325.  * This routine does the work of removing a tuple from an index page.
  326.  */
  327. void
  328. PageIndexTupleDelete(Page page, OffsetNumber offnum)
  329. {
  330. PageHeader phdr;
  331. char    *addr;
  332. ItemId tup;
  333. Size size;
  334. char    *locn;
  335. int nbytes;
  336. int offidx;
  337. phdr = (PageHeader) page;
  338. /* change offset number to offset index */
  339. offidx = offnum - 1;
  340. tup = PageGetItemId(page, offnum);
  341. size = ItemIdGetLength(tup);
  342. size = DOUBLEALIGN(size);
  343. /* location of deleted tuple data */
  344. locn = (char *) (page + ItemIdGetOffset(tup));
  345. /*
  346.  * First, we want to get rid of the pd_linp entry for the index tuple.
  347.  * We copy all subsequent linp's back one slot in the array.
  348.  */
  349. nbytes = phdr->pd_lower -
  350. ((char *) &phdr->pd_linp[offidx + 1] - (char *) phdr);
  351. memmove((char *) &(phdr->pd_linp[offidx]),
  352. (char *) &(phdr->pd_linp[offidx + 1]),
  353. nbytes);
  354. /*
  355.  * Now move everything between the old upper bound (beginning of tuple
  356.  * space) and the beginning of the deleted tuple forward, so that
  357.  * space in the middle of the page is left free.  If we've just
  358.  * deleted the tuple at the beginning of tuple space, then there's no
  359.  * need to do the copy (and bcopy on some architectures SEGV's if
  360.  * asked to move zero bytes).
  361.  */
  362. /* beginning of tuple space */
  363. addr = (char *) (page + phdr->pd_upper);
  364. if (locn != addr)
  365. memmove(addr + size, addr, (int) (locn - addr));
  366. /* adjust free space boundary pointers */
  367. phdr->pd_upper += size;
  368. phdr->pd_lower -= sizeof(ItemIdData);
  369. /* finally, we need to adjust the linp entries that remain */
  370. if (!PageIsEmpty(page))
  371. PageIndexTupleDeleteAdjustLinePointers(phdr, locn, size);
  372. }
  373. /*
  374.  *----------------------------------------------------------------
  375.  * PageIndexTupleDeleteAdjustLinePointers
  376.  *----------------------------------------------------------------
  377.  *
  378.  * Once the line pointers and tuple data have been shifted around
  379.  * on the page, we need to go down the line pointer vector and
  380.  * adjust pointers to reflect new locations.  Anything that used
  381.  * to be before the deleted tuple's data was moved forward by the
  382.  * size of the deleted tuple.
  383.  *
  384.  * This routine does the work of adjusting the line pointers.
  385.  * Location is where the tuple data used to lie; size is how
  386.  * much space it occupied.  We assume that size has been aligned
  387.  * as required by the time we get here.
  388.  *
  389.  * This routine should never be called on an empty page.
  390.  */
  391. static void
  392. PageIndexTupleDeleteAdjustLinePointers(PageHeader phdr,
  393.    char *location,
  394.    Size size)
  395. {
  396. int i;
  397. unsigned offset;
  398. /* location is an index into the page... */
  399. offset = (unsigned) (location - (char *) phdr);
  400. for (i = PageGetMaxOffsetNumber((Page) phdr) - 1; i >= 0; i--)
  401. {
  402. if (phdr->pd_linp[i].lp_off <= offset)
  403. phdr->pd_linp[i].lp_off += size;
  404. }
  405. }