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 libraries 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 $ */
30 * Copyright (c) 1988 by Sun Microsystems, Inc.
37 * B-tree operations: INSERT
41 #include "isam_impl.h"
43 extern int _iskeycmp();
45 void leftkey_up(Btree *, int);
47 static void insert_key(Btree *, char *, int, char *, Blkno);
48 static void splitblock(Btree *, char *, char *, int);
51 /* _isbtree_insert() - Insert entry into B-tree ----------------------------*/
54 _isbtree_insert(Btree *btree, char *key)
56 Keydesc2 *pkeydesc2 = btree->keydesc2;
57 int keylength = pkeydesc2->k2_len;
58 int nkeys; /* Number of keys in the page */
60 char keybuf[MAXKEYSIZE];
63 char *pkp, *pkp2, *pkp3;
64 Bufhdr *kp2bhdr, *kp3bhdr;
71 * Set key comparison function.
73 _iskeycmp_set(pkeydesc2, pkeydesc2->k2_nparts+1); /* +1 for recno field */
76 * Initialize data structure before main loop.
79 memcpy( keybuf,key, keylength);
83 * Starting from the leaf, insert key after current search position.
84 * If necessary make block split and propage changes to upper levels.
85 * Root split is handled differently because we don't want to change
89 for (i = btree->depth - 1; i >= 0; i--) {
91 /* We have to fix the block for update. */
92 btree->bufhdr[i] = _isdisk_refix(btree->bufhdr[i], ISFIXWRITE);
93 pkp = btree->bufhdr[i]->isb_buffer;
95 level = ldshort(pkp + BT_LEVEL_OFF);
96 capac = ldshort(pkp + BT_CAPAC_OFF); /* Block capacity */
97 nkeys = ldshort(pkp + BT_NKEYS_OFF); /* Number of keys in block */
99 assert(level + i + 1 == btree->depth);
100 assert(nkeys <= capac);
102 if (nkeys == capac) {
104 * This block must be split.
105 * Allocate new block, move half of the entries into the new
106 * block, and insert the key into the appropriate
107 * block. If this block is not root, the loop will iterate
108 * to update upper levels.
112 kp2bhdr = _allockpage(btree->fcb, capac, level, &blkno2);
113 pkp2 = kp2bhdr->isb_buffer;
115 halfcapac = (nkeys+1) >> 1; /* Same as nkeys/2 + 1 */
117 splitblock(btree, pkp, pkp2, btree->curpos[i]);
119 if (btree->curpos[i] > halfcapac - 2) {
121 /* Insert entry into right block. */
122 insert_key(btree, pkp2, btree->curpos[i] - halfcapac, keybuf,
126 /* Insert entry into left block. */
127 insert_key(btree, pkp, btree->curpos[i], keybuf, blkno);
129 if (btree->curpos[i] == -1) /* Leftmost entry inserted - */
130 leftkey_up(btree, i); /* propagate to upper levels. */
133 /* Set variables for next loop iteration. */
134 memcpy( keybuf,pkp2 + BT_KEYS_OFF, keylength); /* Leftmost key */
138 * Next loop iteration will insert entry pointing to
139 * new allocated page into next upper level.
144 * Block split is not necessary. Simply insert key into
145 * the block. If the inserted key becomes the leftmost entry
146 * in the block, update upper levels.
149 insert_key(btree, pkp, btree->curpos[i], keybuf, blkno);
151 if (btree->curpos[i] == -1 && i > 0)
152 leftkey_up(btree, i);
154 break; /* from main loop */
163 * Allocate new page. However, to keep root block the same,
164 * the new page is used for the left son of root.
166 * pkp is the new root, pkp3 is the left son,
167 * and pkp3 is the right of the root.
170 kp3bhdr = _allockpage(btree->fcb, capac, 1, &blkno3);
171 pkp3 = kp3bhdr->isb_buffer;
173 memcpy( pkp3,pkp, ISPAGESIZE);
175 stshort((short) getkeyspernode(keylength), pkp + BT_CAPAC_OFF);
176 stshort((short) 0, pkp + BT_NKEYS_OFF);
177 stshort((short)btree->depth, pkp + BT_LEVEL_OFF);
179 insert_key(btree, pkp, -1, pkp3 + BT_KEYS_OFF, blkno3);
180 insert_key(btree, pkp, 0 , keybuf, blkno);
184 /*--------- insert supporting local functions -------------------------------*/
186 /* leftkey_up() - Update upper levels with new leftmost entry -----------*/
188 leftkey_up(Btree *btree, int level)
190 int keylength = btree->keydesc2->k2_len;
194 pkp = btree->bufhdr[level]->isb_buffer;
195 key = pkp + BT_KEYS_OFF; /* Leftmost key */
197 while (--level >= 0) {
199 btree->bufhdr[level] = _isdisk_refix(btree->bufhdr[level], ISFIXWRITE);
200 pkp = btree->bufhdr[level]->isb_buffer;
202 memcpy( pkp + BT_KEYS_OFF + (btree->curpos[level] * keylength),key,
205 if (btree->curpos[level] > 0)
210 /* insert_key - Insert key into block ------------------------*/
212 insert_key(Btree *btree, char *pkp, int pos, char *key, Blkno blkno)
214 int keylength = btree->keydesc2->k2_len;
215 int nkeys = ldshort(pkp + BT_NKEYS_OFF);
216 int capac = ldshort(pkp + BT_CAPAC_OFF);
217 int level = ldshort(pkp + BT_LEVEL_OFF);
219 assert(nkeys < capac);
221 /* Shift nkeys - pos - 1 entries to the right. */
222 /* memmove() handle overlaps correctly */
224 memmove(pkp + BT_KEYS_OFF + (pos + 2) * keylength,
225 pkp + BT_KEYS_OFF + (pos + 1) * keylength,
226 (nkeys - pos - 1) * keylength);
228 /* Copy new key entry into the block. */
229 memcpy( pkp + BT_KEYS_OFF + (pos + 1) * keylength,key, keylength);
231 /* For non-leaf nodes, insert block number into table of down pointers. */
234 memcpy(pkp + ISPAGESIZE - (nkeys + 1) * BLKNOSIZE,
235 pkp + ISPAGESIZE - nkeys * BLKNOSIZE,
236 (nkeys - pos - 1) * BLKNOSIZE);
238 stblkno(blkno, pkp + ISPAGESIZE - (pos + 2) * BLKNOSIZE);
241 stshort((short) (nkeys + 1), pkp + BT_NKEYS_OFF);
244 /* splitblock() - Split block into two -----------------------------*/
246 splitblock(Btree *btree, char *fullpage, char *newpage, int pos)
248 int keylength = btree->keydesc2->k2_len;
249 int nkeys, capac, level;
254 nkeys = ldshort(fullpage + BT_NKEYS_OFF);
255 capac = ldshort(fullpage + BT_NKEYS_OFF);
256 level = ldshort(fullpage + BT_LEVEL_OFF);
258 assert(nkeys == capac);
260 halfcapac = (capac + 1) >> 1; /* same as capac/2 + 1 */
262 if (pos > halfcapac - 2) {
264 /* New entry will go into right page(fullpage). */
265 fullpage_nkeys = halfcapac;
266 newpage_nkeys = halfcapac - 1;
270 /* New entry will go into left page (newpage). */
271 fullpage_nkeys = halfcapac - 1;
272 newpage_nkeys = halfcapac;
275 /* Move newpage_nkeys keys into newpage. */
276 memcpy(newpage + BT_KEYS_OFF,
277 fullpage + BT_KEYS_OFF + fullpage_nkeys * keylength,
278 keylength * newpage_nkeys);
280 /* If non-leaf, move corresponding entries from block number table. */
282 memcpy(newpage + ISPAGESIZE - newpage_nkeys * BLKNOSIZE,
283 fullpage + ISPAGESIZE - nkeys * BLKNOSIZE,
284 newpage_nkeys * BLKNOSIZE);
287 stshort((short) fullpage_nkeys, fullpage + BT_NKEYS_OFF);
288 stshort((short) newpage_nkeys, newpage + BT_NKEYS_OFF);