#include <sys/types.h> #include <stdio.h> #include "btconf.h" #include "btree.h" #include "btintern.h" /* (C) Copyright, 1988, 1989 Marcus J. Ranum All rights reserved This software, its documentation, and supporting files are copyrighted material and may only be distributed in accordance with the terms listed in the COPYRIGHT document. $Log: btinsert.c,v $ * Revision 1.1 90/06/08 16:11:46 mjr * * * Revision 1.1 90/06/06 15:03:43 mjr * * * Revision 1.1 90/06/03 16:23:11 mjr * * * Revision 1.1 90/05/18 23:20:37 mjr * * * Revision 1.1 90/05/15 13:18:30 mjr * Initial revision * * Revision 1.1 90/05/05 15:04:34 mjr * Initial revision * * Revision 1.1 90/03/23 15:03:42 mjr * Initial revision * */ #ifndef lint static char *rcsid = "$Header: /atreus/mjr/hacks/mud/btlib/RCS/btinsert.c,v 1.1 90/06/08 16:11:46 mjr Exp $"; #endif bt_insert(b,key,len,rrn,dupflg) BT_INDEX *b; bt_chrp key; int len; off_t rrn; int dupflg; { struct bt_cache *kp; /* scratch buffer for promoted keys */ struct bt_cache *op; /* old page */ int staklev; off_t ipag; /* page to insert into */ off_t ival; /* index value to insert */ int keyat; /* key # at which to insert */ bt_chrp kp1; /* rotating key buffer pointers */ bt_chrp kp2; off_t ptj; /* junk */ int sr; if(len > BT_MAXK(b)) { bt_errno(b) = BT_KTOOBIG; return(BT_ERR); } if(len <= 0) { bt_errno(b) = BT_ZEROKEY; return(BT_ERR); } if(bt_seekdown(b,key,len) == BT_ERR) return(BT_ERR); /* set current stack level */ staklev = b->sblk.levs - 1; ipag = b->stack[staklev].pg; /* allocate a scratch buffer for the key and promoted key */ /* since all keys will be < pagesiz/2, "split" the buffer */ if((kp = bt_rpage(b,BT_NULL)) == NULL) return(BT_ERR); /* set promotion key ptrs */ kp1 = kp->p; /* split buffers MUST be aligned! */ kp2 = kp->p + DOALIGN(bt_pagesiz(b) / 2); /* *THIS* bullshit should not be necessary */ #ifdef USE_BCOPY (void)bcopy((char *)key,(char *)kp1,len); #endif #ifdef USE_MEMCPY (void)memcpy((char *)kp1,(char *)key,len); #endif #ifdef USE_MOVEMEM (void)movemem((char *)key,(char *)kp1,len); #endif ival = rrn; /* invalidate current notion of where we are in the tree */ b->cpag = BT_NULL; /* set up key location for first page insert */ if((op = bt_rpage(b,ipag)) == NULL) goto bombout; /* locate insert point, check if duplicate */ /* this has the side-effect of setting keyat for the first */ /* run of insert. after the first insert, subsequent key */ /* positions are gotten from the stack, rather than searching */ sr = bt_srchpg(kp1,len,bt_dtype(b),b->cmpfn,&ptj,&keyat,op->p); if(sr == BT_ERR) { bt_errno(b) = BT_PAGESRCH; return(BT_ERR); } /* if the search returned OK, we have a duplicate key and */ /* check to see if dupflg is set - if so, we slam a new */ /* copy of the rrn in, and return immediately. */ if(sr == BT_OK && HIPT(op->p) == BT_NULL) { /* handle dup keys */ if(dupflg == 0) { bt_errno(b) = BT_DUPKEY; goto bombout; } else { /* paste new data ptr in page */ /* and write it out again. */ off_t *p; p = (off_t *)KEYCLD(op->p); *(p + keyat) = rrn; op->flags = BT_CHE_DIRTY; if(bt_wpage(b,op) == BT_ERR || bt_wpage(b,kp) == BT_ERR) return(BT_ERR); /* mark all as well with tree */ bt_clearerr(b); return(BT_OK); } } /* this loop should be comfortably repeated until we perform a */ /* simple insert without a split, which will clean everything up */ /* and return correctly. breaking out indicates a fatal problem */ while(1) { /* here is where we figure out if we need to split, or */ /* if we can just perform a simple insert instead */ if((int)KEYUSE(op->p) + len + sizeof(int) + sizeof(off_t) < bt_pagesiz(b)) { struct bt_cache *tp; if((tp = bt_rpage(b,BT_NULL)) == NULL) goto bombout; ; bt_inspg(kp1,len,&ival,keyat,op->p,tp->p); /* swap the page numbers, invalidate the old, */ /* mark the new as dirty to force a write */ tp->num = op->num; tp->flags = BT_CHE_DIRTY; op->num = BT_NULL; if(bt_wpage(b,op) == BT_ERR || bt_wpage(b,tp) == BT_ERR || bt_wpage(b,kp) == BT_ERR) return(BT_ERR); /* mark all as well with tree */ bt_clearerr(b); return(BT_OK); } else { struct bt_cache *lp; /* new page to hold low keys */ struct bt_cache *hp; /* new page to hold hi keys */ off_t savlft; /* saved left sib page # */ off_t npag; /* new page # */ /* allocate new page for low keys */ if((npag = bt_newpage(b)) == BT_NULL) goto bombout; /* allocate new scratch page for low keys */ if((lp = bt_rpage(b,BT_NULL)) == NULL) goto bombout; /* allocate new scratch page for low keys */ if((hp = bt_rpage(b,BT_NULL)) == NULL) goto bombout; /* and do the thing */ bt_splpg(kp1,len,&ival,keyat,bt_pagesiz(b)/2,op->p,lp->p,hp->p,kp2,&len); /* patch sibs */ LSIB(hp->p) = npag; RSIB(hp->p) = RSIB(op->p); LSIB(lp->p) = LSIB(op->p); savlft = LSIB(op->p); RSIB(lp->p) = ipag; /* mark newly split pages as real */ lp->num = npag; lp->flags = BT_CHE_DIRTY; hp->num = ipag; hp->flags = BT_CHE_DIRTY; op->num = BT_NULL; if(bt_wpage(b,op) == BT_ERR || bt_wpage(b,lp) == BT_ERR || bt_wpage(b,hp) == BT_ERR) goto bombout; /* patch right sib ptr of low pages left sib */ if(savlft != BT_NULL) { if((op = bt_rpage(b,savlft)) == NULL) goto bombout; RSIB(op->p) = npag; op->flags = BT_CHE_DIRTY; if(bt_wpage(b,op) == BT_ERR) goto bombout; } /* since we are not done, the new value */ /* ptr to insert at the next level is that */ /* of the new page we just allocated */ ival = npag; /* if current page was root, make new root */ if(ipag == b->sblk.root) { off_t nr; /* get new page # */ if((nr = bt_newpage(b)) == BT_NULL) goto bombout; /* two scratch pages */ if((op = bt_rpage(b,BT_NULL)) == NULL) goto bombout; if((lp = bt_rpage(b,BT_NULL)) == NULL) goto bombout; /* prime empty root page */ LSIB(op->p) = RSIB(op->p) = BT_NULL; KEYCNT(op->p) = 0; KEYLEN(op->p) = 0; HIPT(op->p) = ipag; /* we already know where to insert */ bt_inspg(kp2,len,&npag,0,op->p,lp->p); /* fix cache stuff and requeue */ op->num = BT_NULL; lp->flags = BT_CHE_DIRTY; lp->num = nr; if(bt_wpage(b,lp) == BT_ERR || bt_wpage(b,kp) == BT_ERR || bt_wpage(b,op) == BT_ERR) goto bombout; /* finally, sync up root */ b->sblk.root = nr; b->sblk.levs++; b->dirt++; if(bt_wsuper(b) == BT_ERR) goto bombout; /* mark all as well with tree */ bt_clearerr(b); /* return - we are done */ return(BT_OK); } } /* still going, pop stack level */ staklev--; keyat = b->stack[staklev].ky; /* current insert page is read from stack */ ipag = b->stack[staklev].pg; if((op = bt_rpage(b,ipag)) == NULL) goto bombout; /* flip key buffer ptrs */ if(kp1 != kp->p) { kp1 = kp->p; kp2 = kp->p + DOALIGN(bt_pagesiz(b) / 2); } else { kp1 = kp->p + DOALIGN(bt_pagesiz(b) / 2); kp2 = kp->p; } } bombout: /* if we reach this point, some fatal error has doubtless occurred */ /* try to bail out, though the tree is almost certainly toast */ if(op != NULL) (void)bt_wpage(b,op); if(kp != NULL) (void)bt_wpage(b,kp); return(BT_ERR); }