jbayer@ispi.UUCP (Jonathan Bayer) (08/09/89)
In response to several requests, I am posting my replacement routines for the btree functions in the CData database library. Please note that while I am posting the bplus routines they are not mine. They are sharware which I received over the net a while ago. They were written and copyrighted by: Hunter and Associates 7050 NW Zinfandel Lane Corvallis, Oregon 97330 (503) 745 - 7186 I am not distributing the documentation for the bplus program. This does NOT do any locking on the files. Therefore, multi-user applications are n/a. #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: wrap.c bplus.c bplus.h # Wrapped by cdbms@ispi on Tue Aug 8 16:29:04 1989 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'wrap.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'wrap.c'\" else echo shar: Extracting \"'wrap.c'\" \(4641 characters\) sed "s/^X//" >'wrap.c' <<'END_OF_FILE' X#include <stdio.h> X#include "cdata.h" X#include "bplus.h" X#include <string.h> X X X/************************************************************************ X * * X * * X * wrap.c V. 1.0 * X * * X * Written by: Jonathan Bayer * X * * X * This is the wrapper interface which interfaces between * X * the BPLUS file indexing program and the standard cdata routines * X * * X * This is released to the public domain, 8/8/1989 * X * * X * Use at your own risk. * X * * X * * X * Use: * X * Compile and link the files bplus.c and wrap.c with your * X * program in place of the btree.c file. * X * * X * * X ************************************************************************/ X Xstatic IX_DESC trees[MXINDEX]; Xstatic int opened[MXINDEX] = {0}; Xstatic ENTRY entry[MXINDEX]; Xint near_mode = FALSE; X Xstatic int k_error = 0; X Xvoid build_b(name, len, Case) Xchar *name; Xint len, Case; X{ XIX_DESC t; X X /* have to implement the case flag */ X X k_error = make_index(name, &t, 1); X k_error = close_index(&t); X X} /* build_b */ X X X Xint btree_init(ndx_name) Xchar *ndx_name; X{ Xint x; X X for (x = 0; x < MXINDEX; x++) { X if (!opened[x]) { X open_index(ndx_name, &trees[x], 1); X opened[x]++; X return x; X } X } X return ERROR; X X} /* btree_init */ X X Xint btree_close(tree) Xint tree; X{ X X if (tree >= MXINDEX || tree < 0 || opened [tree] == 0) X return ERROR; X k_error = close_index(&trees[tree]); X opened[tree] = 0; X if (k_error == IX_OK) return OK; X return ERROR; X} /* btree_close */ X X X Xchar *case_check(k, klen) Xchar *k; Xunsigned klen; X{ Xchar *k1,*k2; X Xklen++; X if (strlen(k) + 1 < klen) { X k1 = (char *) malloc(klen); X strcpy(k1,k); X } else k1 = strdup(k); X X/* if (bheader[trx].Case) { */ X k2 = k1; X while (*k2) { X *k2 = toupper(*k2); X k2++; X } X/* } */ X return k1; X} X X Xint insertkey(tree, key, ad, unique) Xint tree; Xchar *key; XRPTR ad; Xint unique; X{ Xchar *key1; X X /* have to add code to implement the "unique" var */ X X if (tree >= MXINDEX || tree < 0 || opened [tree] == 0) X return ERROR; X X key1 = case_check(key, strlen(key)); /* kludge for now */ X X strcpy(entry[tree].key, key1); X free(key1); X entry[tree].recptr = ad; X k_error = add_key(&entry[tree], &trees[tree]); X X if (k_error == IX_OK) return OK; X return ERROR; X X} /* insertkey */ X X X XRPTR locate(tree, key) Xint tree; Xchar *key; X{ Xchar *key1; X X X if (tree >= MXINDEX || tree < 0 || opened [tree] == 0) X return ERROR; X X key1 = case_check(key, strlen(key)); /* kludge for now */ X X strcpy(entry[tree].key, key1); X free(key1); X k_error = locate_key(&entry[tree], &trees[tree]); X if ((near_mode) && (k_error == IX_FAIL) || X (k_error == IX_OK) ) { X near_mode = FALSE; X return entry[tree].recptr; X } X near_mode = FALSE; X return 0; X} /* locate */ X X X Xint deletekey(tree, key, ad) Xint tree; Xchar *key; XRPTR ad; X{ Xchar *key1; X X if (tree >= MXINDEX || tree < 0 || opened [tree] == 0) X return ERROR; X X key1 = case_check(key, strlen(key)); /* kludge for now */ X X strcpy(entry[tree].key, key1); X free(key1); X entry[tree].recptr = ad; X k_error = delete_key(&entry[tree], &trees[tree]); X if (k_error == IX_OK) return OK; X return ERROR; X X} /* deletekey */ X X X XRPTR firstkey(tree) Xint tree; X{ X X if (tree >= MXINDEX || tree < 0 || opened [tree] == 0) X return ERROR; X k_error = first_key(&trees[tree]); X k_error = next_key(&entry[tree], &trees[tree]); X X if (k_error == IX_OK) return entry[tree].recptr; X return ERROR; X X} /* firstkey */ X X X XRPTR lastkey(tree) Xint tree; X{ X if (tree >= MXINDEX || tree < 0 || opened [tree] == 0) X return ERROR; X k_error = last_key(&trees[tree]); X k_error = prev_key(&entry[tree], &trees[tree]); X X if (k_error == IX_OK) return entry[tree].recptr; X return ERROR; X X} /* lastkey */ X X XRPTR nextkey(tree) Xint tree; X{ X X if (tree >= MXINDEX || tree < 0 || opened [tree] == 0) X return ERROR; X k_error = next_key(&entry[tree], &trees[tree]); X if (k_error == IX_OK) return entry[tree].recptr; X return (RPTR) 0; X X} /* nextkey */ X X XRPTR prevkey(tree) Xint tree; X{ X X if (tree >= MXINDEX || tree < 0 || opened [tree] == 0) X return ERROR; X k_error = prev_key(&entry[tree], &trees[tree]); X if (k_error == IX_OK) return entry[tree].recptr; X return ERROR; X X} /* prevkey */ X X XRPTR currkey(tree) Xint tree; X{ X X if (tree >= MXINDEX || tree < 0 || opened [tree] == 0) X return ERROR; X if (k_error == IX_OK) return entry[tree].recptr; X return ERROR; X X} /* currkey */ X X X Xvoid keyval(tree, key) Xint tree; Xchar *key; X{ X X if (tree >= MXINDEX || tree < 0 || opened [tree] == 0) { X *key = 0; X return; X } X if (k_error == IX_OK) { X strcpy(key, entry[tree].key); X } else *key = '\0'; X X} /* keyval */ END_OF_FILE if test 4641 -ne `wc -c <'wrap.c'`; then echo shar: \"'wrap.c'\" unpacked with wrong size! fi # end of 'wrap.c' fi if test -f 'bplus.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'bplus.c'\" else echo shar: Extracting \"'bplus.c'\" \(24536 characters\) sed "s/^X//" >'bplus.c' <<'END_OF_FILE' X/********************************************************************/ X/* */ X/* BPLUS file indexing program - Version 1.1 */ X/* */ X/* A "shareware program" */ X/* */ X/* */ X/* Copyright (C) 1987 by */ X/* */ X/* Hunter and Associates */ X/* 7050 NW Zinfandel Lane */ X/* Corvallis, Oregon 97330 */ X/* (503) 745 - 7186 */ X/* */ X/********************************************************************/ X X X#include <stdio.h> X#include <fcntl.h> X#ifndef M_XENIX X#include <io.h> X#endif X#include <sys/types.h> /* delete this line for Turbo C */ X#include <sys/stat.h> X#include <string.h> X#include <errno.h> X#include <malloc.h> X#include "bplus.h" X X#ifndef M_XENIX X#include <stddef.h> X#endif X X X X/* macros, constants, data types */ X X#define NULLREC (-1L) X#define FREE_BLOCK (-2) X X#define ENT_ADR(pb,off) ((ENTRY*)((char*)((pb)->entries) + off)) X#define ENT_SIZE(pe) strlen((pe)->key) + 1 + 2 * sizeof(RECPOS) X#define BUFDIRTY(j) (mci->cache[j].dirty) X#define BUFHANDLE(j) (mci->cache[j].handle) X#define BUFBLOCK(j) (mci->cache[j].mb) X#define BUFCOUNT(j) (mci->cache[j].count) X#define CB(j) (pci->pos[j].cblock) X#define CO(j) (pci->pos[j].coffset) X X X X/* declare some global variables */ X XIX_DESC *pci; XIX_BUFFER bt_buffer; XIX_BUFFER *mci = &bt_buffer; XBLOCK *block_ptr; XBLOCK *spare_block; Xint cache_ptr = 0; Xint cache_init = 0; Xint split_size = IXB_SPACE; Xint comb_size = (IXB_SPACE/2); X Xvoid pascal error(int, long); Xvoid pascal read_if(long, char *, int); Xvoid pascal write_if(int, long, char *, int); Xint pascal creat_if(char *); Xint pascal open_if(char *); Xvoid pascal close_if(int); Xvoid pascal update_block(void); Xvoid pascal init_cache(void); Xint pascal find_cache(RECPOS); Xint pascal new_cache(void); Xvoid pascal load_cache(RECPOS); Xvoid pascal get_cache(RECPOS); Xvoid pascal retrieve_block(int, RECPOS); Xint pascal prev_entry(int); Xint pascal next_entry(int); Xint pascal copy_entry(ENTRY *, ENTRY *); Xint pascal scan_blk(int); Xint pascal last_entry(void); Xint pascal write_free( RECPOS, BLOCK *); XRECPOS pascal get_free(void); Xint pascal find_block(ENTRY *, int *); Xvoid pascal movedown(BLOCK *, int, int); Xvoid pascal moveup(BLOCK *, int, int); Xvoid pascal ins_block(BLOCK *, ENTRY *, int); Xvoid pascal del_block(BLOCK *, int); Xint pascal split(int, ENTRY *, ENTRY *); Xvoid pascal ins_level(int, ENTRY *); Xint pascal insert_ix(ENTRY *, IX_DESC *); Xint pascal find_ix(ENTRY *, IX_DESC *, int); Xint pascal combineblk(RECPOS, int); Xvoid pascal replace_entry(ENTRY *); Xvoid print_blk(BLOCK *); X X#ifdef M_XENIX Xlong lseek(); X X Xchar *memmove ( s1, s2, n) Xchar *s1, *s2; Xint n; X{ Xchar *b = (char *)malloc(n); X X memcpy(b,s2,n); X memcpy(s1,b,n); X free(b); X X} X#endif X X /* ATTENTION MICROSOFT USERS */ X /* Microsoft changed the memcpy */ X /* library routine in the C 5.0 */ X /* compiler. The following macro */ X /* must be used for Microsoft 5.0 */ X /* and the Quick C compiler. */ X X#define memcpy memmove X X X/* file I/O for B-PLUS module */ X Xstatic void pascal error(j, l) X int j; X long l; X { X static char *msg[3] = {"ERROR - CANNOT OPEN/CLOSE FILE", X "ERROR WHILE READING FILE", X "ERROR WHILE WRITING FILE"}; X printf("\n %s - Record Number %ld\n", msg[j], l); X if (l == 0) { X printf("\nerrno: %d\n",errno); X} X exit(1); X } /* error */ X X Xvoid pascal read_if(start, buf, nwrt) X long start; X char *buf; X int nwrt; X { X long err; X err = start - lseek(pci->ixfile, start, SEEK_SET); X if (err == 0) err = nwrt - read(pci->ixfile, buf, nwrt); X if (err != 0) error(1, start); X } /* read_if */ X X Xvoid pascal write_if(handle, start, buf, nwrt) X int handle; X long start; X char *buf; X int nwrt; X { X long err; X err = start - lseek(handle, start, SEEK_SET); X if (err == 0) err = nwrt - write(handle, buf, nwrt); X if (err != 0) error(2, start); X } /* write_if */ X X Xint pascal creat_if(fn) X char *fn; X { X int ret; X ret = open(fn,O_RDWR|O_CREAT|O_TRUNC|O_BINARY,S_IWRITE | S_IREAD); X if (ret < 0) error(0,0L); X return (ret); X } /* creat_if */ X X Xint pascal open_if(fn) X char *fn; X { X int ret; X ret = open(fn,O_RDWR|O_BINARY); X if (ret < 1) error(0,0L); X return (ret); X } /* open_if */ X X Xvoid pascal close_if(handle) X int handle; X { X if(close(handle) < 0) error(2,0L); X } /* close_if */ X X Xint cdecl open_index(name, pix, dup) X char *name; X IX_DESC *pix; X int dup; X { X pci = pix; X pci->ixfile = open_if(name); X pci->duplicate = dup; X read_if(0L,(char *)&(pix->root), (sizeof(BLOCK) + sizeof(IX_DISK))); X if (!cache_init) X { X init_cache(); X cache_init = 1; X } X first_key(pix); X return ( IX_OK ); X } /* open_index */ X X Xint cdecl close_index(pix) X IX_DESC *pix; X { X int i; X write_if(pix->ixfile, 0L,(char *)&(pix->root), X (sizeof(BLOCK) + sizeof(IX_DISK))); X for (i = 0; i < NUM_BUFS; i++) X if (BUFHANDLE(i) == pix->ixfile) X { X if (BUFDIRTY(i)) X { X write_if(BUFHANDLE(i), X BUFBLOCK(i).brec, X (char *) &BUFBLOCK(i), X sizeof(BLOCK)); X BUFDIRTY(i) = 0; X } X BUFBLOCK(i).brec = NULLREC; X } X close_if(pix->ixfile); X return( IX_OK ); X } /* close_index */ X X Xint cdecl make_index(name, pix, dup) X char *name; X IX_DESC *pix; X int dup; X { X pci = pix; X pci->ixfile = creat_if(name); X pci->duplicate = dup; X pci->dx.nl = 1; X pci->dx.ff = NULLREC; X pci->level = 0; X CO(0) = -1; X CB(0) = 0L; X pci->root.brec = 0L; X pci->root.bend = 0; X pci->root.p0 = NULLREC; X write_if(pci->ixfile, 0L,(char *)&(pix->root), X (sizeof(BLOCK) + sizeof(IX_DISK))); X if (!cache_init) X { X init_cache(); X cache_init = 1; X } X first_key(pix); X return ( IX_OK ); X } /* make_index */ X X X/* cache I/O for BPLUS */ X Xvoid pascal update_block() X { X if (block_ptr != &(pci->root)) X BUFDIRTY(cache_ptr) = 1; X } /* update_block */ X X Xvoid pascal init_cache() X { X register int j; X for (j = 0; j < NUM_BUFS; j++) X { BUFDIRTY(j) = 0; X BUFCOUNT(j) = 0; X BUFBLOCK(j).brec = NULLREC; X } X } /* init_cache */ X X Xint pascal find_cache(r) X RECPOS r; X { X register int j; X for (j = 0; j < NUM_BUFS; j++) X { X if((BUFBLOCK(j).brec == r) && (BUFHANDLE(j) == pci->ixfile)) X { cache_ptr = j; X return (1); X } } X return (-1); X } /* find_cache */ X X Xint pascal new_cache() X { X register int i; X i = (cache_ptr + 1) % NUM_BUFS; X if (BUFDIRTY(i)) write_if(BUFHANDLE(i), X BUFBLOCK(i).brec, X (char *) &BUFBLOCK(i), X sizeof(BLOCK)); X BUFHANDLE(i) = pci->ixfile; X BUFDIRTY(i) = 0; X return (i); X } /* new_cache */ X X Xvoid pascal load_cache(r) X RECPOS r; X { X cache_ptr = new_cache(); X read_if(r, (char *)&BUFBLOCK(cache_ptr), sizeof(BLOCK)); X } /* load_cache */ X X Xvoid pascal get_cache(r) X RECPOS r; X { X if (find_cache(r) < 0) X load_cache(r); X block_ptr = &BUFBLOCK(cache_ptr); X } /* get_cache */ X X Xvoid pascal retrieve_block(j, r) X int j; X RECPOS r; X { X if (j == 0) X block_ptr = &(pci->root); X else get_cache(r); X CB(j) = block_ptr->brec; X } /* retrieve_block */ X X X/* low level functions of BPLUS */ X Xint pascal prev_entry(off) X int off; X { X if (off <= 0) X { X off = -1; X CO(pci->level) = off; X } X else X off = scan_blk(off); X return(off); X } /* prev_entry */ X X Xint pascal next_entry(off) X int off; X { X if (off == -1) X off = 0; X else X { X if (off < block_ptr->bend) X off += ENT_SIZE(ENT_ADR(block_ptr,off)); X } X CO(pci->level) = off; X return (off); X } /* next_entry */ X X Xint pascal copy_entry(to, from) X ENTRY *to; X ENTRY *from; X { X int me; X me = ENT_SIZE(from); X memcpy(to, from, me); X } /* copy_entry */ X X Xint pascal scan_blk(n) X int n; X { X register int off, last; X off = 0; X last = -1; X while (off < n ) X { last = off; X off += ENT_SIZE(ENT_ADR(block_ptr,off)); X } X CO(pci->level) = last; X return (last); X } /* scan_blk */ X X Xint pascal last_entry() X { X return( scan_blk(block_ptr->bend) ); X } /* last_entry */ X X X/* maintain list of free index blocks */ X Xint pascal write_free(r, pb) X RECPOS r; X BLOCK *pb; X { X pb->p0 = FREE_BLOCK; X pb->brec = pci->dx.ff; X write_if(pci->ixfile, r, (char *) pb, sizeof(BLOCK)); X pci->dx.ff = r; X } /* write_free */ X X X#ifdef M_XENIX Xlong filelength(f) Xint f; X{ Xstruct stat buf; X X fstat(f, &buf); X return buf.st_size; X} X#endif X X X XRECPOS pascal get_free() X { X RECPOS r, rt; X X r = pci->dx.ff; X if ( r != NULLREC ) X { read_if(r, (char *)&rt, sizeof( RECPOS )); X pci->dx.ff = rt; X } X else X r = filelength (pci->ixfile); X return (r); X } /* get_free */ X X X/* general BPLUS block level functions */ X Xint pascal find_block(pe, poff) X ENTRY *pe; X int *poff; X { X register int pos, nextpos, ret; X pos = -1; X nextpos = 0; X ret = 1; X while ( nextpos < block_ptr->bend) X { X ret = strcmp((char *)(pe->key), X (char *)(ENT_ADR(block_ptr, nextpos)->key)); X if (ret <= 0) X { X if (ret == 0) pos = nextpos; X break; X } X pos = nextpos; X nextpos = next_entry(pos); X } X CO(pci->level) = pos; X *poff = pos; X return (ret); X } /* find_block */ X X Xvoid pascal movedown(pb, off, n) X BLOCK *pb; X int off; X int n; X { X memcpy(ENT_ADR(pb, off), X ENT_ADR(pb, off + n), X pb -> bend - (off + n)); X } /* movedown */ X X Xvoid pascal moveup(pb, off, n) X BLOCK *pb; X int off; X int n; X { X memcpy(ENT_ADR(pb, off + n), X ENT_ADR(pb, off), X pb->bend - off); X } /* moveup */ X X Xvoid pascal ins_block(pb, pe, off) X BLOCK *pb; X ENTRY *pe; X int off; X { X int size; X size = ENT_SIZE(pe); X moveup(pb,off,size); X copy_entry(ENT_ADR(pb,off),pe); X pb->bend += size; X } /* ins_block */ X X Xvoid pascal del_block(pb, off) X BLOCK *pb; X int off; X { X int ne; X ne = ENT_SIZE(ENT_ADR(pb, off)); X movedown(pb, off, ne); X pb->bend -= ne; X } /* del_block */ X X X/* position at start/end of index */ X Xint cdecl first_key(pix) X IX_DESC *pix; X { X pci = pix; X block_ptr = &(pci->root); X CB(0) = 0L; X CO(0) = -1; X pci->level = 0; X while(block_ptr->p0 != NULLREC) X { X retrieve_block(++(pci->level), block_ptr->p0); X CO(pci->level) = -1; X } X return ( IX_OK ); X } /* first_key */ X X Xint cdecl last_key(pix) X IX_DESC *pix; X { X long ads; X X pci = pix; X block_ptr = &(pci->root); X CB(0) = 0L; X pci->level = 0; X if(last_entry() >= 0) X { X while ((ads = ENT_ADR(block_ptr,last_entry())->idxptr) != NULLREC) X retrieve_block(++(pci->level), ads); X } X CO(pci->level) = block_ptr->bend; X return ( IX_OK ); X } /* last_key */ X X X/* get next, previous entries */ X Xint cdecl next_key(pe, pix) X ENTRY *pe; X IX_DESC *pix; X { X RECPOS address; X X pci = pix; X retrieve_block(pci->level, CB(pci->level)); X if(CO(pci->level) == -1) address = block_ptr->p0; X else address = ENT_ADR(block_ptr, CO(pci->level))->idxptr; X while (address != NULLREC) X { X retrieve_block(++(pci->level), address); X CO(pci->level) = -1; X address = block_ptr->p0; X } X next_entry(CO(pci->level)); X if (CO(pci->level) == block_ptr->bend) X { X do X { if(pci->level == 0) X { X last_key(pci); Xprev_key(pe, pix); X return (EOIX); X } X --(pci->level); X retrieve_block(pci->level, CB(pci->level)); X next_entry(CO(pci->level)); X } while (CO(pci->level) == block_ptr->bend); X } X copy_entry(pe, ENT_ADR(block_ptr, CO(pci->level))); X return ( IX_OK ); X } /* next_key */ X X Xint cdecl prev_key(pe, pix) X ENTRY *pe; X IX_DESC *pix; X { X RECPOS address; X pci = pix; X retrieve_block(pci->level, CB(pci->level)); X prev_entry(CO(pci->level)); X if (CO(pci->level) == -1) X address = block_ptr->p0; X else X address = ENT_ADR(block_ptr, CO(pci->level))->idxptr; X if (address != NULLREC) X { do X { X retrieve_block(++(pci->level), address); X address = ENT_ADR(block_ptr, last_entry())->idxptr; X } while (address != NULLREC); X } X if (CO(pci->level) == -1) X { do X { X if(pci->level == 0) X { X first_key(pci); X return (EOIX); X } X --(pci->level); X } while (CO(pci->level) == -1); X retrieve_block(pci->level, CB(pci->level)); X } X copy_entry(pe, ENT_ADR(block_ptr, CO(pci->level))); X return ( IX_OK ); X } /* prev_key */ X X X/* insert new entries into tree */ X Xint pascal split(l, pe, e) X int l; X ENTRY *pe; X ENTRY *e; X { X int half, ins_pos, size; X ins_pos = CO(pci->level); X half = scan_blk(block_ptr->bend / 2 + sizeof(RECPOS)); X if (half == ins_pos) X *e = *pe; X else X { X copy_entry(e, ENT_ADR(block_ptr, half)); X size = ENT_SIZE(e); X movedown(block_ptr, half, size); X block_ptr->bend -= size; X } X spare_block = &BUFBLOCK(new_cache()); X memcpy(spare_block->entries, X ENT_ADR(block_ptr,half), X block_ptr->bend - half); X spare_block->brec = get_free(); X spare_block->bend = block_ptr->bend - half; X spare_block->p0 = e->idxptr; X block_ptr->bend = half; X e->idxptr = spare_block->brec; X if (ins_pos < half) X ins_block(block_ptr,pe,ins_pos); X else if (ins_pos > half) X { X ins_pos -= ENT_SIZE(e); X ins_block(spare_block,pe,ins_pos - half); X CB(l) = e->idxptr; X CO(l) = CO(l) - half; X } X write_if(pci->ixfile, spare_block->brec, X (char *) spare_block, sizeof(BLOCK)); X } /* split */ X X Xvoid pascal ins_level(l, e) X int l; X ENTRY *e; X { X int i; X if ( l < 0) X { for (i = 1; i < MAX_LEVELS; i++) X { CO(MAX_LEVELS - i) = CO(MAX_LEVELS - i - 1); X CB(MAX_LEVELS - i) = CB(MAX_LEVELS - i - 1); X } X memcpy(spare_block, &(pci->root), sizeof(BLOCK)); X spare_block->brec = get_free(); X write_if(pci->ixfile, spare_block->brec, X (char *) spare_block, sizeof(BLOCK)); X pci->root.p0 = spare_block->brec; X copy_entry((ENTRY *) (pci->root.entries), e); X pci->root.bend = ENT_SIZE(e); X CO(0) = 0; X pci->level = 0; X (pci->dx.nl)++; X } X else ins_block(block_ptr,e,CO(l)); X } /* ins_level */ X X Xint pascal insert_ix(pe, pix) X ENTRY *pe; X IX_DESC *pix; X { X ENTRY e, ee; X int h; X h = 0; X pci = pix; X ee = *pe; X do X { X if(CO(pci->level) >= 0) X CO(pci->level) += X ENT_SIZE(ENT_ADR(block_ptr, CO(pci->level))); X else X CO(pci->level) = 0; X update_block(); X if( (block_ptr->bend + ENT_SIZE(&ee)) <= split_size) X { X ins_level(pci->level, &ee); X break; X } X else X { X h = 1; X split(pci->level,&ee, &e); X ee = e; X pci->level--; X if (pci->level < 0) X { X ins_level(pci->level, &e); X break; X } X retrieve_block(pci->level, CB(pci->level)); X } X } X while (1); X if (h) find_ix(pe, pix, 0); X return ( IX_OK ); X } /* insert_ix */ X X X/* BPLUS find and add key functions */ X Xint pascal find_ix(pe, pix, find) X ENTRY *pe; X IX_DESC *pix; X int find; X { X int level, off, ret; X RECPOS ads; X X pci = pix; X ads = 0L; X level = ret = 0; X while (ads != NULLREC) X { pci->level = level; X retrieve_block(level, ads); X if (find_block(pe, &off) == 0) ret = 1; X if (ret && find) break; X if (off == -1) X ads = block_ptr->p0; X else X ads = ENT_ADR(block_ptr, off)->idxptr; X CO(level++) = off; X } X return ( ret ); X } /* find_ix */ X X Xint cdecl find_key(pe, pix) X ENTRY *pe; X IX_DESC *pix; X { X int ret; X ret = find_ix(pe, pix, 1); X if ( ret ) copy_entry(pe, ENT_ADR(block_ptr, CO(pci->level))); X return ( ret ); X } /* find_key */ X X Xint cdecl add_key(pe, pix) X ENTRY *pe; X IX_DESC *pix; X { X int ret; X ret = find_ix(pe, pix, 0); X if ( ret && (pci->duplicate == 0)) return ( IX_FAIL ); X pe->idxptr = NULLREC; X return (insert_ix(pe, pix)); X } /* add_key */ X X Xint cdecl locate_key(pe, pix) X ENTRY *pe; X IX_DESC *pix; X { X int ret; X X ret = find_ix(pe, pix, 1); X if (ret) copy_entry(pe, ENT_ADR(block_ptr, CO(pci->level))); X else if (next_key(pe,pix) == EOIX) ret = EOIX; X return ( ret ); X } /* locate_key */ X X Xint cdecl find_exact(pe, pix) X ENTRY *pe; X IX_DESC * pix; X { X int ret; X ENTRY e; X copy_entry(&e, pe); X ret = find_key(&e, pix); X if ( ret && pci->duplicate) X { X do X { X ret = (e.recptr == pe->recptr); X if( !ret ) ret = next_key(&e, pci); X if (ret) ret = (strcmp(e.key, pe->key) == 0); X if ( !ret ) return ( 0 ); X } while ( !ret ); X } X copy_entry(pe, &e); X return ( ret ); X } /* find_exact */ X X X/* BPLUS delete key functions */ X Xint cdecl delete_key(pe, pix) X ENTRY *pe; X IX_DESC *pix; X { X ENTRY e; X RECPOS ads; X int h, leveli, levelf; X if (!find_exact(pe, pix)) return( IX_FAIL ); X h = 1; X if ((ads = pe->idxptr) != NULLREC) X { X leveli = pci->level; X do X { X retrieve_block(++(pci->level), ads); X CO(pci->level) = -1; X } X while ((ads = block_ptr->p0) != NULLREC); X CO(pci->level) = 0; X copy_entry(&e, ENT_ADR(block_ptr, CO(pci->level))); X levelf = pci->level; X pci->level = leveli; X replace_entry(&e); X pci->level = levelf; X } X while ( h ) X { X retrieve_block(pci->level, CB(pci->level)); X del_block(block_ptr, CO(pci->level)); X update_block(); X if ( (pci->level == 0) && (block_ptr->bend == 0)) X /* tree was reduced in height */ X { X if (pci->root.p0 != NULLREC) X { X retrieve_block(++pci->level, pci->root.p0); X memcpy(&(pci->root), block_ptr, sizeof(BLOCK)); X (pci->dx.nl)--; X write_free(block_ptr->brec, block_ptr); X BUFDIRTY(cache_ptr) = 0; X BUFHANDLE(cache_ptr) = 0; X } X break; X } X h = (block_ptr->bend < comb_size) && (pci->level > 0); X if ( h ) X h = combineblk(CB(pci->level), block_ptr->bend); X } X find_ix(pe,pix,0); X return( IX_OK ); X } /* delete_key */ X X Xint pascal combineblk(ads, size) X RECPOS ads; X int size; X { X ENTRY e; X RECPOS address; X int esize, off, ret, saveoff, ibuff; X ret = 0; X saveoff = CO(--(pci->level)); X retrieve_block(pci->level, CB(pci->level)); X if ((off = next_entry( saveoff )) < block_ptr->bend) X /* combine with page on right */ X { X if ( (ENT_SIZE(ENT_ADR(block_ptr, off)) + size) < split_size) X { X copy_entry(&e, ENT_ADR(block_ptr, off)); X address = ENT_ADR(block_ptr, CO(pci->level))->idxptr; X retrieve_block(++pci->level, address); X ibuff = cache_ptr; X spare_block = block_ptr; X retrieve_block(pci->level, ads); X esize = ENT_SIZE(&e); X if(((block_ptr->bend + spare_block->bend + esize) >= split_size) X && (spare_block->bend <= block_ptr->bend + esize)) X return( ret ); X e.idxptr = spare_block->p0; X ins_block(block_ptr, &e, block_ptr->bend); X update_block(); X if ((block_ptr->bend + spare_block->bend) < split_size) X /* combine the blocks */ X { X memcpy(ENT_ADR(block_ptr, block_ptr->bend), X ENT_ADR(spare_block, 0), X spare_block->bend); X block_ptr->bend += spare_block->bend; X write_free(spare_block->brec, spare_block); X BUFDIRTY(ibuff) = 0; X BUFHANDLE(ibuff) = 0; X --pci->level; X ret = 1; X } X else X /* move an entry up to replace the one moved */ X { X copy_entry(&e, ENT_ADR(spare_block, 0)); X esize = ENT_SIZE(&e); X movedown(spare_block, 0, esize); X spare_block->bend -= esize; X spare_block->p0 = e.idxptr; X BUFDIRTY(ibuff) = 1; X --(pci->level); X replace_entry(&e); X } X } X } X else X /* move from page on left */ X { X if ( (ENT_SIZE(ENT_ADR(block_ptr, CO(pci->level))) + size) X < split_size) X { X copy_entry(&e, ENT_ADR(block_ptr, saveoff)); X off = prev_entry(saveoff); X if (CO(pci->level) == -1) address = block_ptr->p0; X else address = ENT_ADR(block_ptr, CO(pci->level))->idxptr; X retrieve_block(++pci->level, address); X off = last_entry(); X ibuff = cache_ptr; X spare_block = block_ptr; X retrieve_block(pci->level, ads); X esize = ENT_SIZE(&e); X if(((block_ptr->bend + spare_block->bend + esize) >= split_size) X && (spare_block->bend <= block_ptr->bend + esize)) X return( ret ); X BUFDIRTY(ibuff) = 1; X CO(pci->level) = 0; X e.idxptr = block_ptr->p0; X ins_block(block_ptr, &e, 0); X if ((block_ptr->bend + spare_block->bend) < split_size) X /* combine the blocks */ X { X memcpy(ENT_ADR(spare_block, spare_block->bend), X ENT_ADR(block_ptr, 0), X block_ptr->bend); X spare_block->bend += block_ptr->bend; X write_free(block_ptr->brec, block_ptr); X BUFDIRTY(cache_ptr) = 0; X BUFHANDLE(cache_ptr) = 0; X CO(--(pci->level)) = saveoff; X ret = 1; X } X else X /* move an entry up to replace the one moved */ X { X block_ptr->p0 = ENT_ADR(spare_block,off)->idxptr; X copy_entry(&e, ENT_ADR(spare_block, off)); X spare_block->bend = off; X update_block(); X CO(--(pci->level)) = saveoff; X replace_entry(&e); X } X } X } X return ( ret ); X } /* combineblk */ X X Xvoid pascal replace_entry(pe) X ENTRY *pe; X { X retrieve_block(pci->level, CB(pci->level)); X pe->idxptr = ENT_ADR(block_ptr, CO(pci->level))->idxptr; X del_block(block_ptr, CO(pci->level)); X prev_entry(CO(pci->level)); X insert_ix(pe, pci); X } /* replace_entry */ X END_OF_FILE if test 24536 -ne `wc -c <'bplus.c'`; then echo shar: \"'bplus.c'\" unpacked with wrong size! fi # end of 'bplus.c' fi if test -f 'bplus.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'bplus.h'\" else echo shar: Extracting \"'bplus.h'\" \(2838 characters\) sed "s/^X//" >'bplus.h' <<'END_OF_FILE' X X/* bplus.h - data structures and constants */ X X X#define IX_OK 1 X#define IX_FAIL 0 X#define EOIX (-2) X#define MAXKEY 100 X#define NUM_BUFS 8 X#define MAX_LEVELS 8 X#define IXB_SIZE 1024 X#define IXB_SPACE (IXB_SIZE - sizeof(int) - sizeof(long) * 2) X Xtypedef long RECPOS; X Xtypedef struct /* entry structure in index */ X { RECPOS idxptr; /* points to lower index level */ X RECPOS recptr; /* points to data record */ X char key[MAXKEY]; /* start of record key */ X } ENTRY; X Xtypedef struct /* index record format */ X { RECPOS brec; /* position in index file */ X /* or location of next free block */ X int bend; /* first unused block location */ X RECPOS p0; /* points to next level */ X char entries[IXB_SPACE]; /* here are the key entries */ X } BLOCK; X Xtypedef struct /* disk file info */ X { RECPOS ff; /* location of first free block */ X int nl; /* number of index levels */ X } IX_DISK; X Xtypedef struct /* memory buffer pool of indx blks */ X { int dirty; /* true if changed */ X int handle; /* index file handle */ X int count; /* number of times referenced */ X BLOCK mb; X } MEMBLOCK; X Xtypedef struct X { MEMBLOCK cache [ NUM_BUFS ]; X } IX_BUFFER; X Xtypedef struct /* in-memory index descriptor */ X { int ixfile; X int level; /* level in btree */ X int duplicate; /* no duplicate keys if 0 */ X struct X { RECPOS cblock; /* position in index file */ X int coffset; /* current offset within block */ X } pos [ MAX_LEVELS ]; X BLOCK root; /* root index record */ X IX_DISK dx; X } IX_DESC; X X#if defined(M_XENIX) && !defined(M_I386) X#define cdecl X#endif X Xint cdecl open_index(char *,IX_DESC *, int); Xint cdecl close_index(IX_DESC *); Xint cdecl make_index(char *,IX_DESC *, int); Xint cdecl first_key(IX_DESC *); Xint cdecl last_key(IX_DESC *); Xint cdecl next_key(ENTRY *, IX_DESC *); Xint cdecl prev_key(ENTRY *, IX_DESC *); Xint cdecl find_key(ENTRY *, IX_DESC *); Xint cdecl add_key(ENTRY *, IX_DESC *); Xint cdecl locate_key(ENTRY *, IX_DESC *); Xint cdecl delete_key(ENTRY *, IX_DESC *); Xint cdecl find_exact(ENTRY *, IX_DESC *); X X X#ifdef M_XENIX X X#define SEEK_SET 0 X#define SEEK_END 2 X#define O_BINARY 0 X X#endif X END_OF_FILE if test 2838 -ne `wc -c <'bplus.h'`; then echo shar: \"'bplus.h'\" unpacked with wrong size! fi # end of 'bplus.h' fi echo shar: End of shell archive. exit 0 -- Jonathan Bayer Beware: The light at the end of the Intelligent Software Products, Inc. tunnel may be an oncoming dragon 500 Oakwood Ave. ...uunet!ispi!root Roselle Park, NJ 07204 (201) 245-5922 jbayer@ispi.UUCP