bt_put.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  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_put.c /main/3 1996/06/11 17:12:56 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_put.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 <stdio.h>
  65. #include <stdlib.h>
  66. #include <string.h>
  67. #include <db.h>
  68. #include "btree.h"
  69. static EPG *bt_fast __P((BTREE *, const DBT *, const DBT *, int *));
  70. /*
  71. * __BT_PUT -- Add a btree item to the tree.
  72. *
  73. * Parameters:
  74. * dbp: pointer to access method
  75. * key: key
  76. * data: data
  77. * flag: R_NOOVERWRITE
  78. *
  79. * Returns:
  80. * RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key is already in the
  81. * tree and R_NOOVERWRITE specified.
  82. */
  83. int
  84. __bt_put(const DB *dbp, DBT *key, const DBT *data, u_int flags)
  85. {
  86. BTREE *t;
  87. DBT tkey, tdata;
  88. EPG *e = NULL;
  89. PAGE *h;
  90. indx_t index, nxtindex;
  91. pgno_t pg;
  92. size_t nbytes;
  93. int dflags, exact, status;
  94. char *dest, db[NOVFLSIZE], kb[NOVFLSIZE];
  95. t = dbp->internal;
  96. /* Toss any page pinned across calls. */
  97. if (t->bt_pinned != NULL) {
  98. mpool_put(t->bt_mp, t->bt_pinned, 0);
  99. t->bt_pinned = NULL;
  100. }
  101. switch (flags) {
  102. case R_CURSOR:
  103. if (!ISSET(t, B_SEQINIT))
  104. goto einval;
  105. if (ISSET(t, B_DELCRSR))
  106. goto einval;
  107. break;
  108. case 0:
  109. case R_NOOVERWRITE:
  110. break;
  111. default:
  112. einval: errno = EINVAL;
  113. return (RET_ERROR);
  114. }
  115. if (ISSET(t, B_RDONLY)) {
  116. errno = EPERM;
  117. return (RET_ERROR);
  118. }
  119. /*
  120. * If the key/data won't fit on a page, store it on indirect pages.
  121. * Only store the key on the overflow page if it's too big after the
  122. * data is on an overflow page.
  123. *
  124. * XXX
  125. * If the insert fails later on, these pages aren't recovered.
  126. */
  127. dflags = 0;
  128. if (key->size + data->size > t->bt_ovflsize) {
  129. if (key->size > t->bt_ovflsize) {
  130. storekey: if (__ovfl_put(t, key, &pg) == RET_ERROR)
  131. return (RET_ERROR);
  132. tkey.data = kb;
  133. tkey.size = NOVFLSIZE;
  134. memmove(kb, &pg, sizeof(pgno_t));
  135. memmove(kb + sizeof(pgno_t),
  136. &key->size, sizeof(size_t));
  137. dflags |= P_BIGKEY;
  138. key = &tkey;
  139. }
  140. if (key->size + data->size > t->bt_ovflsize) {
  141. if (__ovfl_put(t, data, &pg) == RET_ERROR)
  142. return (RET_ERROR);
  143. tdata.data = db;
  144. tdata.size = NOVFLSIZE;
  145. memmove(db, &pg, sizeof(pgno_t));
  146. memmove(db + sizeof(pgno_t),
  147. &data->size, sizeof(size_t));
  148. dflags |= P_BIGDATA;
  149. data = &tdata;
  150. }
  151. if (key->size + data->size > t->bt_ovflsize)
  152. goto storekey;
  153. }
  154. /* Replace the cursor. */
  155. if (flags == R_CURSOR) {
  156. if ((h = mpool_get(t->bt_mp, t->bt_bcursor.pgno, 0)) == NULL)
  157. return (RET_ERROR);
  158. index = t->bt_bcursor.index;
  159. goto delete;
  160. }
  161. /*
  162. * Find the key to delete, or, the location at which to insert. Bt_fast
  163. * and __bt_search pin the returned page.
  164. */
  165. if (t->bt_order == NOT || (e = bt_fast(t, key, data, &exact)) == NULL)
  166. if ((e = __bt_search(t, key, &exact)) == NULL)
  167. return (RET_ERROR);
  168. h = e->page;
  169. index = e->index;
  170. /*
  171. * Add the specified key/data pair to the tree. If an identical key
  172. * is already in the tree, and R_NOOVERWRITE is set, an error is
  173. * returned. If R_NOOVERWRITE is not set, the key is either added (if
  174. * duplicates are permitted) or an error is returned.
  175. *
  176. * Pages are split as required.
  177. */
  178. switch (flags) {
  179. case R_NOOVERWRITE:
  180. if (!exact)
  181. break;
  182. /*
  183. * One special case is if the cursor references the record and
  184. * it's been flagged for deletion. Then, we delete the record,
  185. * leaving the cursor there -- this means that the inserted
  186. * record will not be seen in a cursor scan.
  187. */
  188. if (ISSET(t, B_DELCRSR) && t->bt_bcursor.pgno == h->pgno &&
  189. t->bt_bcursor.index == index) {
  190. CLR(t, B_DELCRSR);
  191. goto delete;
  192. }
  193. mpool_put(t->bt_mp, h, 0);
  194. return (RET_SPECIAL);
  195. default:
  196. if (!exact || !ISSET(t, B_NODUPS))
  197. break;
  198. delete: if (__bt_dleaf(t, h, index) == RET_ERROR) {
  199. mpool_put(t->bt_mp, h, 0);
  200. return (RET_ERROR);
  201. }
  202. break;
  203. }
  204. /*
  205. * If not enough room, or the user has put a ceiling on the number of
  206. * keys permitted in the page, split the page. The split code will
  207. * insert the key and data and unpin the current page. If inserting
  208. * into the offset array, shift the pointers up.
  209. */
  210. nbytes = NBLEAFDBT(key->size, data->size);
  211. if (h->upper - h->lower < nbytes + sizeof(indx_t)) {
  212. if ((status = __bt_split(t, h, key,
  213. data, dflags, nbytes, index)) != RET_SUCCESS)
  214. return (status);
  215. goto success;
  216. }
  217. if (index < (nxtindex = NEXTINDEX(h)))
  218. memmove(h->linp + index + 1, h->linp + index,
  219. (nxtindex - index) * sizeof(indx_t));
  220. h->lower += sizeof(indx_t);
  221. h->linp[index] = h->upper -= nbytes;
  222. dest = (char *)h + h->upper;
  223. WR_BLEAF(dest, key, data, dflags);
  224. if (t->bt_order == NOT) {
  225. if (h->nextpg == P_INVALID) {
  226. if (index == NEXTINDEX(h) - 1) {
  227. t->bt_order = FORWARD;
  228. t->bt_last.index = index;
  229. t->bt_last.pgno = h->pgno;
  230. }
  231. } else if (h->prevpg == P_INVALID) {
  232. if (index == 0) {
  233. t->bt_order = BACK;
  234. t->bt_last.index = 0;
  235. t->bt_last.pgno = h->pgno;
  236. }
  237. }
  238. }
  239. mpool_put(t->bt_mp, h, MPOOL_DIRTY);
  240. success:
  241. if (flags == R_SETCURSOR) {
  242. t->bt_bcursor.pgno = e->page->pgno;
  243. t->bt_bcursor.index = e->index;
  244. }
  245. SET(t, B_MODIFIED);
  246. return (RET_SUCCESS);
  247. }
  248. #ifdef STATISTICS
  249. u_long bt_cache_hit, bt_cache_miss;
  250. #endif
  251. /*
  252. * BT_FAST -- Do a quick check for sorted data.
  253. *
  254. * Parameters:
  255. * t: tree
  256. * key: key to insert
  257. *
  258. * Returns:
  259. * EPG for new record or NULL if not found.
  260. */
  261. static EPG *
  262. bt_fast(BTREE *t, const DBT *key, const DBT *data, int *exactp)
  263. {
  264. static EPG e;
  265. PAGE *h;
  266. size_t nbytes;
  267. int cmp;
  268. if ((h = mpool_get(t->bt_mp, t->bt_last.pgno, 0)) == NULL) {
  269. t->bt_order = NOT;
  270. return (NULL);
  271. }
  272. e.page = h;
  273. e.index = t->bt_last.index;
  274. /*
  275. * If won't fit in this page or have too many keys in this page, have
  276. * to search to get split stack.
  277. */
  278. nbytes = NBLEAFDBT(key->size, data->size);
  279. if (h->upper - h->lower < nbytes + sizeof(indx_t))
  280. goto miss;
  281. if (t->bt_order == FORWARD) {
  282. if (e.page->nextpg != P_INVALID)
  283. goto miss;
  284. if (e.index != NEXTINDEX(h) - 1)
  285. goto miss;
  286. if ((cmp = __bt_cmp(t, key, &e)) < 0)
  287. goto miss;
  288. t->bt_last.index = cmp ? ++e.index : e.index;
  289. } else {
  290. if (e.page->prevpg != P_INVALID)
  291. goto miss;
  292. if (e.index != 0)
  293. goto miss;
  294. if ((cmp = __bt_cmp(t, key, &e)) > 0)
  295. goto miss;
  296. t->bt_last.index = 0;
  297. }
  298. *exactp = cmp == 0;
  299. #ifdef STATISTICS
  300. ++bt_cache_hit;
  301. #endif
  302. return (&e);
  303. miss:
  304. #ifdef STATISTICS
  305. ++bt_cache_miss;
  306. #endif
  307. t->bt_order = NOT;
  308. mpool_put(t->bt_mp, h, 0);
  309. return (NULL);
  310. }