2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
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)
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
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /*%% (c) Copyright 1993, 1994 Hewlett-Packard Company */
24 /*%% (c) Copyright 1993, 1994 International Business Machines Corp. */
25 /*%% (c) Copyright 1993, 1994 Sun Microsystems, Inc. */
26 /*%% (c) Copyright 1993, 1994 Novell, Inc. */
27 /*%% $XConsortium: isbtree2.c /main/3 1995/10/23 11:36:02 rswiston $ */
29 static char sccsid[] = "@(#)isbtree2.c 1.5 89/07/17 Copyr 1988 Sun Micro";
33 * Copyright (c) 1988 by Sun Microsystems, Inc.
40 * B-tree operations: INSERT
44 #include "isam_impl.h"
46 extern int _iskeycmp();
50 /* _isbtree_insert() - Insert entry into B-tree ----------------------------*/
53 _isbtree_insert(btree, key)
54 register Btree *btree;
57 Keydesc2 *pkeydesc2 = btree->keydesc2;
58 int keylength = pkeydesc2->k2_len;
59 int nkeys; /* Number of keys in the page */
61 char keybuf[MAXKEYSIZE];
64 char *pkp, *pkp2, *pkp3;
65 Bufhdr *kp2bhdr, *kp3bhdr;
72 * Set key comparison function.
74 _iskeycmp_set(pkeydesc2, pkeydesc2->k2_nparts+1); /* +1 for recno field */
77 * Initialize data structure before main loop.
80 memcpy( keybuf,key, keylength);
84 * Starting from the leaf, insert key after current search position.
85 * If necessary make block split and propage changes to upper levels.
86 * Root split is handled differently because we don't want to change
90 for (i = btree->depth - 1; i >= 0; i--) {
92 /* We have to fix the block for update. */
93 btree->bufhdr[i] = _isdisk_refix(btree->bufhdr[i], ISFIXWRITE);
94 pkp = btree->bufhdr[i]->isb_buffer;
96 level = ldshort(pkp + BT_LEVEL_OFF);
97 capac = ldshort(pkp + BT_CAPAC_OFF); /* Block capacity */
98 nkeys = ldshort(pkp + BT_NKEYS_OFF); /* Number of keys in block */
100 assert(level + i + 1 == btree->depth);
101 assert(nkeys <= capac);
103 if (nkeys == capac) {
105 * This block must be split.
106 * Allocate new block, move half of the entries into the new
107 * block, and insert the key into the appropriate
108 * block. If this block is not root, the loop will iterate
109 * to update upper levels.
113 kp2bhdr = _allockpage(btree->fcb, capac, level, &blkno2);
114 pkp2 = kp2bhdr->isb_buffer;
116 halfcapac = (nkeys+1) >> 1; /* Same as nkeys/2 + 1 */
118 splitblock(btree, pkp, pkp2, btree->curpos[i]);
120 if (btree->curpos[i] > halfcapac - 2) {
122 /* Insert entry into right block. */
123 insert_key(btree, pkp2, btree->curpos[i] - halfcapac, keybuf,
127 /* Insert entry into left block. */
128 insert_key(btree, pkp, btree->curpos[i], keybuf, blkno);
130 if (btree->curpos[i] == -1) /* Leftmost entry inserted - */
131 leftkey_up(btree, i); /* propagate to upper levels. */
134 /* Set variables for next loop iteration. */
135 memcpy( keybuf,pkp2 + BT_KEYS_OFF, keylength); /* Leftmost key */
139 * Next loop iteration will insert entry pointing to
140 * new allocated page into next upper level.
145 * Block split is not necessary. Simply insert key into
146 * the block. If the inserted key becomes the leftmost entry
147 * in the block, update upper levels.
150 insert_key(btree, pkp, btree->curpos[i], keybuf, blkno);
152 if (btree->curpos[i] == -1 && i > 0)
153 leftkey_up(btree, i);
155 break; /* from main loop */
164 * Allocate new page. However, to keep root block the same,
165 * the new page is used for the left son of root.
167 * pkp is the new root, pkp3 is the left son,
168 * and pkp3 is the right of the root.
171 kp3bhdr = _allockpage(btree->fcb, capac, 1, &blkno3);
172 pkp3 = kp3bhdr->isb_buffer;
174 memcpy( pkp3,pkp, ISPAGESIZE);
176 stshort((short) getkeyspernode(keylength), pkp + BT_CAPAC_OFF);
177 stshort((short) 0, pkp + BT_NKEYS_OFF);
178 stshort((short)btree->depth, pkp + BT_LEVEL_OFF);
180 insert_key(btree, pkp, -1, pkp3 + BT_KEYS_OFF, blkno3);
181 insert_key(btree, pkp, 0 , keybuf, blkno);
185 /*--------- insert supporting local functions -------------------------------*/
187 /* leftkey_up() - Update upper levels with new leftmost entry -----------*/
188 leftkey_up(btree, level)
189 register Btree *btree;
192 int keylength = btree->keydesc2->k2_len;
196 pkp = btree->bufhdr[level]->isb_buffer;
197 key = pkp + BT_KEYS_OFF; /* Leftmost key */
199 while (--level >= 0) {
201 btree->bufhdr[level] = _isdisk_refix(btree->bufhdr[level], ISFIXWRITE);
202 pkp = btree->bufhdr[level]->isb_buffer;
204 memcpy( pkp + BT_KEYS_OFF + (btree->curpos[level] * keylength),key,
207 if (btree->curpos[level] > 0)
212 /* insert_key - Insert key into block ------------------------*/
213 Static insert_key(btree, pkp, pos, key, blkno)
214 register Btree *btree;
220 int keylength = btree->keydesc2->k2_len;
221 int nkeys = ldshort(pkp + BT_NKEYS_OFF);
222 int capac = ldshort(pkp + BT_CAPAC_OFF);
223 int level = ldshort(pkp + BT_LEVEL_OFF);
225 assert(nkeys < capac);
227 /* Shift nkeys - pos - 1 entries to the right. */
228 /* memmove() handle overlaps correctly */
230 memmove(pkp + BT_KEYS_OFF + (pos + 2) * keylength,
231 pkp + BT_KEYS_OFF + (pos + 1) * keylength,
232 (nkeys - pos - 1) * keylength);
234 /* Copy new key entry into the block. */
235 memcpy( pkp + BT_KEYS_OFF + (pos + 1) * keylength,key, keylength);
237 /* For non-leaf nodes, insert block number into table of down pointers. */
240 memcpy(pkp + ISPAGESIZE - (nkeys + 1) * BLKNOSIZE,
241 pkp + ISPAGESIZE - nkeys * BLKNOSIZE,
242 (nkeys - pos - 1) * BLKNOSIZE);
244 stblkno(blkno, pkp + ISPAGESIZE - (pos + 2) * BLKNOSIZE);
247 stshort((short) (nkeys + 1), pkp + BT_NKEYS_OFF);
250 /* splitblock() - Split block into two -----------------------------*/
251 splitblock(btree, fullpage, newpage, pos)
252 register Btree *btree;
253 register char *fullpage, *newpage;
256 int keylength = btree->keydesc2->k2_len;
257 int nkeys, capac, level;
262 nkeys = ldshort(fullpage + BT_NKEYS_OFF);
263 capac = ldshort(fullpage + BT_NKEYS_OFF);
264 level = ldshort(fullpage + BT_LEVEL_OFF);
266 assert(nkeys == capac);
268 halfcapac = (capac + 1) >> 1; /* same as capac/2 + 1 */
270 if (pos > halfcapac - 2) {
272 /* New entry will go into right page(fullpage). */
273 fullpage_nkeys = halfcapac;
274 newpage_nkeys = halfcapac - 1;
278 /* New entry will go into left page (newpage). */
279 fullpage_nkeys = halfcapac - 1;
280 newpage_nkeys = halfcapac;
283 /* Move newpage_nkeys keys into newpage. */
284 memcpy(newpage + BT_KEYS_OFF,
285 fullpage + BT_KEYS_OFF + fullpage_nkeys * keylength,
286 keylength * newpage_nkeys);
288 /* If non-leaf, move corresponding entries from block number table. */
290 memcpy(newpage + ISPAGESIZE - newpage_nkeys * BLKNOSIZE,
291 fullpage + ISPAGESIZE - nkeys * BLKNOSIZE,
292 newpage_nkeys * BLKNOSIZE);
295 stshort((short) fullpage_nkeys, fullpage + BT_NKEYS_OFF);
296 stshort((short) newpage_nkeys, newpage + BT_NKEYS_OFF);