# include # include # include # include # include # include SCCSID(@(#)ndxsearch.c 8.1 12/31/84) /* ** NDXSEARCH -- search an ISAM directory ** ** Looks for an available page, if this would force out a page from ** the relation it adds its own. Searches each level of the dirctory ** for the lowest (highest) page on which the key could occur if mode ** is < (>) 0. At each level the number of keys on the page is checked ** if it is <= SEARCHFUDGE a linear sharch is done, otherwize a binary ** search is preformed. If the full key matches exactly the seach ** can stop. Note that the keys tell the minimum value on that page. ** ** Parameters: ** d - pointer to descriptor of open relation ** tid - returns tid of page to start (end) looking ** key - to look for ** mode - < 0 lowkey, > 0 hikey ** keyok - true if all keys are assumed to be set ** ** Returns: ** -2 - pageflush failure ** -1 - get_page failure ** 0 - success ** ** Side Effects: ** causes I/O */ # define SEARCHFUDGE 6 /* # of linenos to do a binary search */ ndxsearch(d, tid, tuple, mode, keyok) DESC *d; register TID *tid; char tuple[]; int mode; int keyok; { register int i; long pageid; int j, keylen, dno, partialkey; char *p; int pagerr; struct accessparam relparm; int top; register bottom; extern char *get_addr(); pagerr = 0; paramd(d, &relparm); /* get domains in key order */ /* assume fullkey is given */ partialkey = FALSE; /* remove any key domains not given by the user */ if (!keyok) { for (i = 0; dno = relparm.keydno[i]; i++) { if (d->relgiven[dno]) continue; relparm.keydno[i] = 0; partialkey = TRUE; break; } } /* if the first key isn't given, just return else search directory */ if (relparm.keydno[0] != 0) { /* The actual ISAM directory search must be performed */ pageid = d->reldum.relprim; stuff_page(tid, &pageid); Acclock = FALSE; do { if (pagerr = get_page(d, tid)) break; /* fatal error */ Acc_head->bufstatus |= BUF_DIRECT; /* don't get confused */ bottom = 0; top = Acc_head->nxtlino - 1; if (top >= SEARCHFUDGE) /* we are past breakeven */ { while (top != bottom) /* binary search */ { tid->line_id = ((1 + top - bottom) >> 1) + bottom; /* get to half way point */ p = get_addr(tid); for (j = 0; dno = relparm.keydno[j]; j++) { keylen = d->relfrml[dno] & I1MASK; if (i = icompare(&tuple[d->reloff[dno]], p, d->relfrmt[dno], keylen)) break; p += keylen; } /* if key is below directory, then we are in the bottom half */ if (i < 0 || (i == 0 && partialkey && mode < 0)) top = (tid->line_id & I1MASK) - 1; else if (i == 0 && !partialkey) { bottom = (tid->line_id & I1MASK); break; } else bottom = (tid->line_id & I1MASK); } } else /* do a linar search */ { for (tid->line_id = 0; (tid->line_id & I1MASK) < Acc_head->nxtlino; tid->line_id++) { p = get_addr(tid); for (i = 0; dno = relparm.keydno[i]; i++) { keylen = d->relfrml[dno] & I1MASK; if (j = icompare(&tuple[d->reloff[dno]], p, d->relfrmt[dno], keylen)) break; p += keylen; } /* if key is below directory, then we have passed the position */ if (j < 0) break; /* if lowkey search on partial key matches, then done */ if (j == 0 && partialkey && mode < 0) break; bottom = tid->line_id; if (j == 0 && mode < 0) break; } } pageid = Acc_head->ovflopg + bottom; stuff_page(tid, &pageid); } while (Acc_head->mainpg); /* if at level zero then done */ Acclock = TRUE; } tid->line_id = -1; return (pagerr); }