bt_seq.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. /*
  2. * CDE - Common Desktop Environment
  3. *
  4. * Copyright (c) 1993-2012, The Open Group. All rights reserved.
  5. *
  6. * These libraries and programs are free software; you can
  7. * redistribute them and/or modify them under the terms of the GNU
  8. * Lesser General Public License as published by the Free Software
  9. * Foundation; either version 2 of the License, or (at your option)
  10. * any later version.
  11. *
  12. * These libraries and programs are distributed in the hope that
  13. * they will be useful, but WITHOUT ANY WARRANTY; without even the
  14. * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  15. * PURPOSE. See the GNU Lesser General Public License for more
  16. * details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with these libraries and programs; if not, write
  20. * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
  21. * Floor, Boston, MA 02110-1301 USA
  22. */
  23. /* $XConsortium: bt_seq.c /main/3 1996/06/11 17:13:05 cde-hal $ */
  24. /*-
  25. * Copyright (c) 1990, 1993
  26. * The Regents of the University of California. All rights reserved.
  27. *
  28. * This code is derived from software contributed to Berkeley by
  29. * Mike Olson.
  30. *
  31. * Redistribution and use in source and binary forms, with or without
  32. * modification, are permitted provided that the following conditions
  33. * are met:
  34. * 1. Redistributions of source code must retain the above copyright
  35. * notice, this list of conditions and the following disclaimer.
  36. * 2. Redistributions in binary form must reproduce the above copyright
  37. * notice, this list of conditions and the following disclaimer in the
  38. * documentation and/or other materials provided with the distribution.
  39. * 3. All advertising materials mentioning features or use of this software
  40. * must display the following acknowledgement:
  41. * This product includes software developed by the University of
  42. * California, Berkeley and its contributors.
  43. * 4. Neither the name of the University nor the names of its contributors
  44. * may be used to endorse or promote products derived from this software
  45. * without specific prior written permission.
  46. *
  47. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  48. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  49. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  50. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  51. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  52. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  53. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  54. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  55. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  56. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  57. * SUCH DAMAGE.
  58. */
  59. #if defined(LIBC_SCCS) && !defined(lint)
  60. static char sccsid[] = "@(#)bt_seq.c 8.2 (Berkeley) 9/7/93";
  61. #endif /* LIBC_SCCS and not lint */
  62. #include <sys/types.h>
  63. #include <errno.h>
  64. #include <stddef.h>
  65. #include <stdio.h>
  66. #include <stdlib.h>
  67. #include <db.h>
  68. #include "btree.h"
  69. static int bt_seqadv __P((BTREE *, EPG *, int));
  70. static int bt_seqset __P((BTREE *, EPG *, DBT *, int));
  71. /*
  72. * Sequential scan support.
  73. *
  74. * The tree can be scanned sequentially, starting from either end of the tree
  75. * or from any specific key. A scan request before any scanning is done is
  76. * initialized as starting from the least node.
  77. *
  78. * Each tree has an EPGNO which has the current position of the cursor. The
  79. * cursor has to survive deletions/insertions in the tree without losing its
  80. * position. This is done by noting deletions without doing them, and then
  81. * doing them when the cursor moves (or the tree is closed).
  82. */
  83. /*
  84. * __BT_SEQ -- Btree sequential scan interface.
  85. *
  86. * Parameters:
  87. * dbp: pointer to access method
  88. * key: key for positioning and return value
  89. * data: data return value
  90. * flags: R_CURSOR, R_FIRST, R_LAST, R_NEXT, R_PREV.
  91. *
  92. * Returns:
  93. * RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key.
  94. */
  95. int
  96. __bt_seq(const DB *dbp, DBT *key, DBT *data, u_int flags)
  97. {
  98. BTREE *t;
  99. EPG e;
  100. int status;
  101. t = dbp->internal;
  102. /* Toss any page pinned across calls. */
  103. if (t->bt_pinned != NULL) {
  104. mpool_put(t->bt_mp, t->bt_pinned, 0);
  105. t->bt_pinned = NULL;
  106. }
  107. /*
  108. * If scan unitialized as yet, or starting at a specific record, set
  109. * the scan to a specific key. Both bt_seqset and bt_seqadv pin the
  110. * page the cursor references if they're successful.
  111. */
  112. switch(flags) {
  113. case R_NEXT:
  114. case R_PREV:
  115. if (ISSET(t, B_SEQINIT)) {
  116. status = bt_seqadv(t, &e, flags);
  117. break;
  118. }
  119. /* FALLTHROUGH */
  120. case R_CURSOR:
  121. case R_FIRST:
  122. case R_LAST:
  123. status = bt_seqset(t, &e, key, flags);
  124. break;
  125. default:
  126. errno = EINVAL;
  127. return (RET_ERROR);
  128. }
  129. if (status == RET_SUCCESS) {
  130. status = __bt_ret(t, &e, key, data);
  131. /* Update the actual cursor. */
  132. t->bt_bcursor.pgno = e.page->pgno;
  133. t->bt_bcursor.index = e.index;
  134. /*
  135. * If the user is doing concurrent access, we copied the
  136. * key/data, toss the page.
  137. */
  138. if (ISSET(t, B_DB_LOCK))
  139. mpool_put(t->bt_mp, e.page, 0);
  140. else
  141. t->bt_pinned = e.page;
  142. SET(t, B_SEQINIT);
  143. }
  144. return (status);
  145. }
  146. /*
  147. * BT_SEQSET -- Set the sequential scan to a specific key.
  148. *
  149. * Parameters:
  150. * t: tree
  151. * ep: storage for returned key
  152. * key: key for initial scan position
  153. * flags: R_CURSOR, R_FIRST, R_LAST, R_NEXT, R_PREV
  154. *
  155. * Side effects:
  156. * Pins the page the cursor references.
  157. *
  158. * Returns:
  159. * RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key.
  160. */
  161. static int
  162. bt_seqset(BTREE *t, EPG *ep, DBT *key, int flags)
  163. {
  164. EPG *e;
  165. PAGE *h;
  166. pgno_t pg;
  167. int exact;
  168. /*
  169. * Delete any already deleted record that we've been saving because
  170. * the cursor pointed to it. Since going to a specific key, should
  171. * delete any logically deleted records so they aren't found.
  172. */
  173. if (ISSET(t, B_DELCRSR) && __bt_crsrdel(t, &t->bt_bcursor))
  174. return (RET_ERROR);
  175. /*
  176. * Find the first, last or specific key in the tree and point the cursor
  177. * at it. The cursor may not be moved until a new key has been found.
  178. */
  179. switch(flags) {
  180. case R_CURSOR: /* Keyed scan. */
  181. /*
  182. * Find the first instance of the key or the smallest key which
  183. * is greater than or equal to the specified key. If run out
  184. * of keys, return RET_SPECIAL.
  185. */
  186. if (key->data == NULL || key->size == 0) {
  187. errno = EINVAL;
  188. return (RET_ERROR);
  189. }
  190. e = __bt_first(t, key, &exact); /* Returns pinned page. */
  191. if (e == NULL)
  192. return (RET_ERROR);
  193. /*
  194. * If at the end of a page, skip any empty pages and find the
  195. * next entry.
  196. */
  197. if (e->index == NEXTINDEX(e->page)) {
  198. h = e->page;
  199. do {
  200. pg = h->nextpg;
  201. mpool_put(t->bt_mp, h, 0);
  202. if (pg == P_INVALID)
  203. return (RET_SPECIAL);
  204. if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
  205. return (RET_ERROR);
  206. } while (NEXTINDEX(h) == 0);
  207. e->index = 0;
  208. e->page = h;
  209. }
  210. *ep = *e;
  211. break;
  212. case R_FIRST: /* First record. */
  213. case R_NEXT:
  214. /* Walk down the left-hand side of the tree. */
  215. for (pg = P_ROOT;;) {
  216. if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
  217. return (RET_ERROR);
  218. if (h->flags & (P_BLEAF | P_RLEAF))
  219. break;
  220. pg = GETBINTERNAL(h, 0)->pgno;
  221. mpool_put(t->bt_mp, h, 0);
  222. }
  223. /* Skip any empty pages. */
  224. while (NEXTINDEX(h) == 0 && h->nextpg != P_INVALID) {
  225. pg = h->nextpg;
  226. mpool_put(t->bt_mp, h, 0);
  227. if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
  228. return (RET_ERROR);
  229. }
  230. if (NEXTINDEX(h) == 0) {
  231. mpool_put(t->bt_mp, h, 0);
  232. return (RET_SPECIAL);
  233. }
  234. ep->page = h;
  235. ep->index = 0;
  236. break;
  237. case R_LAST: /* Last record. */
  238. case R_PREV:
  239. /* Walk down the right-hand side of the tree. */
  240. for (pg = P_ROOT;;) {
  241. if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
  242. return (RET_ERROR);
  243. if (h->flags & (P_BLEAF | P_RLEAF))
  244. break;
  245. pg = GETBINTERNAL(h, NEXTINDEX(h) - 1)->pgno;
  246. mpool_put(t->bt_mp, h, 0);
  247. }
  248. /* Skip any empty pages. */
  249. while (NEXTINDEX(h) == 0 && h->prevpg != P_INVALID) {
  250. pg = h->prevpg;
  251. mpool_put(t->bt_mp, h, 0);
  252. if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
  253. return (RET_ERROR);
  254. }
  255. if (NEXTINDEX(h) == 0) {
  256. mpool_put(t->bt_mp, h, 0);
  257. return (RET_SPECIAL);
  258. }
  259. ep->page = h;
  260. ep->index = NEXTINDEX(h) - 1;
  261. break;
  262. }
  263. return (RET_SUCCESS);
  264. }
  265. /*
  266. * BT_SEQADVANCE -- Advance the sequential scan.
  267. *
  268. * Parameters:
  269. * t: tree
  270. * flags: R_NEXT, R_PREV
  271. *
  272. * Side effects:
  273. * Pins the page the new key/data record is on.
  274. *
  275. * Returns:
  276. * RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key.
  277. */
  278. static int
  279. bt_seqadv(BTREE *t, EPG *e, int flags)
  280. {
  281. EPGNO *c, delc;
  282. PAGE *h;
  283. indx_t index;
  284. pgno_t pg;
  285. /* Save the current cursor if going to delete it. */
  286. c = &t->bt_bcursor;
  287. if (ISSET(t, B_DELCRSR))
  288. delc = *c;
  289. if ((h = mpool_get(t->bt_mp, c->pgno, 0)) == NULL)
  290. return (RET_ERROR);
  291. /*
  292. * Find the next/previous record in the tree and point the cursor at it.
  293. * The cursor may not be moved until a new key has been found.
  294. */
  295. index = c->index;
  296. switch(flags) {
  297. case R_NEXT: /* Next record. */
  298. if (++index == NEXTINDEX(h)) {
  299. do {
  300. pg = h->nextpg;
  301. mpool_put(t->bt_mp, h, 0);
  302. if (pg == P_INVALID)
  303. return (RET_SPECIAL);
  304. if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
  305. return (RET_ERROR);
  306. } while (NEXTINDEX(h) == 0);
  307. index = 0;
  308. }
  309. break;
  310. case R_PREV: /* Previous record. */
  311. if (index-- == 0) {
  312. do {
  313. pg = h->prevpg;
  314. mpool_put(t->bt_mp, h, 0);
  315. if (pg == P_INVALID)
  316. return (RET_SPECIAL);
  317. if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
  318. return (RET_ERROR);
  319. } while (NEXTINDEX(h) == 0);
  320. index = NEXTINDEX(h) - 1;
  321. }
  322. break;
  323. }
  324. e->page = h;
  325. e->index = index;
  326. /*
  327. * Delete any already deleted record that we've been saving because the
  328. * cursor pointed to it. This could cause the new index to be shifted
  329. * down by one if the record we're deleting is on the same page and has
  330. * a larger index.
  331. */
  332. if (ISSET(t, B_DELCRSR)) {
  333. CLR(t, B_DELCRSR); /* Don't try twice. */
  334. if (c->pgno == delc.pgno && c->index > delc.index)
  335. --c->index;
  336. if (__bt_crsrdel(t, &delc))
  337. return (RET_ERROR);
  338. }
  339. return (RET_SUCCESS);
  340. }
  341. /*
  342. * __BT_CRSRDEL -- Delete the record referenced by the cursor.
  343. *
  344. * Parameters:
  345. * t: tree
  346. *
  347. * Returns:
  348. * RET_ERROR, RET_SUCCESS
  349. */
  350. int
  351. __bt_crsrdel(BTREE *t, EPGNO *c)
  352. {
  353. PAGE *h;
  354. int status;
  355. CLR(t, B_DELCRSR); /* Don't try twice. */
  356. if ((h = mpool_get(t->bt_mp, c->pgno, 0)) == NULL)
  357. return (RET_ERROR);
  358. status = __bt_dleaf(t, h, c->index);
  359. mpool_put(t->bt_mp, h, MPOOL_DIRTY);
  360. return (status);
  361. }