1: #include <btree.h> 2: #include <ingres.h> 3: #include <opsys.h> 4: #include <sccs.h> 5: 6: SCCSID(@(#)btree_util.c 8.2 1/31/86) 7: 8: /* Trace up to the root of the BTree, incrementing (or decrementing) all 9: ** key values. 10: ** 11: ** Parameters : 12: ** tree - BTree filename (I) 13: ** block - starting node from which path is traced (I) 14: ** inc - either +1 or -1 (I) 15: */ 16: 17: tracepath(rootpage, block, inc) 18: 19: long rootpage; 20: register struct locator *block; 21: register int inc; 22: { 23: struct locator p, child; 24: 25: if (block->pageno != rootpage) /* if at root, no need for adjustment */ 26: { 27: bmove(block, &child, sizeof(struct locator)); 28: 29: /* trace up to root node */ 30: do 31: { 32: p.pageno = child.page.parent; 33: parentkey(child.pageno, &p); 34: p.page.node.intnode.key[p.offset] += inc; 35: write_node(p.pageno, &p.page); 36: bmove(&p, &child, sizeof(struct locator)); 37: } while (p.pageno != rootpage); 38: } 39: } 40: 41: /* Determines which key/ptr pair is the parent of the given page 42: ** 43: ** Parameters : 44: ** tree - BTree filename (I) 45: ** block - page number of child (I) 46: ** prt - information about the parent of the child (I, O) 47: ** 48: */ 49: 50: parentkey(block, prt) 51: 52: long block; 53: register struct locator *prt; 54: { 55: register int i; 56: 57: get_node(prt->pageno, &prt->page); 58: /* find pointer in parent which references desired block */ 59: for (i = 0; prt->page.node.intnode.ptr[i] != block && i < prt->page.nelmts; ++i) 60: continue; 61: 62: if (i == prt->page.nelmts) 63: syserr("parentkey: child = %ld", block); 64: prt->offset = i; 65: return(0); 66: } 67: 68: /* Retrieve a node from the BTree 69: ** 70: ** Parameters : 71: ** tree - BTree filename (I) 72: ** pagenum - page number of page to be retrieved (I) 73: ** buffer - buffer into which page is retrieved (O) 74: */ 75: 76: get_node(pagenum, buffer) 77: 78: long pagenum; 79: register struct BTreeNode *buffer; 80: { 81: extern int Btree_fd; 82: 83: if ( lseek(Btree_fd, pagenum * PGSIZE, 0) == -1 ) 84: syserr("GET_NODE: seek to %ld failed",pagenum); 85: if (read(Btree_fd, buffer, sizeof *buffer) != sizeof *buffer) 86: syserr("GET_NODE: read btree, page %ld", pagenum); 87: } 88: 89: /* Write a node into the BTree file name 90: ** 91: ** Parameters : 92: ** tree - BTree filename (I) 93: ** pagenum - page number of page to be written (I) 94: ** buffer - buffer containing page to be written (I) 95: */ 96: 97: write_node(pagenum, buffer) 98: 99: long pagenum; 100: register struct BTreeNode *buffer; 101: { 102: extern int Btree_fd; 103: 104: lseek(Btree_fd, pagenum * PGSIZE, 0); 105: if (write(Btree_fd, buffer, sizeof *buffer) != sizeof *buffer) 106: syserr("WRITE_NODE: write btree, page %ld", pagenum); 107: } 108: 109: /* Retrieves a new page from the BTree file. If there is an empty page 110: ** in the file, that page is used. Otherwise, a new page is added to 111: ** the end of the file. 112: ** 113: ** Parameters : 114: ** tree - BTree filename (I) 115: ** 116: ** Returns : 117: ** page number of new page 118: */ 119: 120: long 121: new_page(tree) 122: 123: char *tree; 124: { 125: int i; 126: long freepage, newpage; 127: struct BTreeNode page, root, garbage; 128: struct stat fileinfo; 129: extern DESC Btreesec; 130: 131: get_node(RT, &root); 132: freepage = root.parent; 133: if (freepage == 0) 134: /* no free pages in file, add a new page to the end */ 135: { 136: /* determine page number of page at very end of file */ 137: stat(tree, &fileinfo); 138: newpage = fileinfo.st_size / PGSIZE; 139: write_node(newpage, &page); 140: } 141: else 142: /* use first free page, adjusting free page chain */ 143: { 144: newpage = freepage; 145: get_node(newpage, &garbage); 146: root.parent = garbage.parent; 147: write_node(RT, &root); 148: } 149: return(newpage); 150: } 151: 152: /* Returns an empty file to the empty file list. The head of the list 153: ** is indicated through the parent of the root and linked together 154: ** through the parents of the empty pages. 155: ** 156: ** Parameters : 157: ** tree - BTree filename (I) 158: ** pagenum - page number of empty page (I) 159: */ 160: 161: return_page(pagenum) 162: 163: long pagenum; 164: { 165: struct BTreeNode root, freepage; 166: 167: /* indicate that page is free by inserting its page number at the 168: ** head of the free page list */ 169: get_node(RT, &root); 170: get_node(pagenum, &freepage); 171: freepage.parent = root.parent; 172: freepage.depth = 0; 173: write_node(pagenum, &freepage); 174: root.parent = pagenum; 175: write_node(RT, &root); 176: } 177: 178: /* 179: ** Determine the lid that corresponds to a given position in the B-Tree. 180: ** 181: ** Parameters : 182: ** tree - BTree name (I) 183: ** tidloc - location in BTree (I) 184: ** 185: ** Returns : 186: ** lid value 187: */ 188: get_lid(tidloc, lid) 189: 190: TID *tidloc; 191: long lid[]; 192: { 193: static struct locator tid; 194: register int i, j; 195: long l, child; 196: 197: do 198: { 199: /* determine where in BTree to search */ 200: pluck_page(tidloc, &tid.pageno); 201: 202: get_node(tid.pageno, (char *) &tid.page); 203: tid.offset = tid.page.node.leafnode.back_ptr[tidloc->line_id & I1MASK]; 204: 205: if (tid.offset > tid.page.nelmts - 1) 206: syserr("get_lid: bad tid location %ld, tid.offset=%d, tid.page.nelmts=%d", *tidloc, tid.offset,tid.page.nelmts); 207: 208: /* scan through leaf */ 209: for (l = 1, i = tid.offset; i > 0; ++l, --i) 210: continue; 211: /* trace up to root, adding keys */ 212: while (!tid.page.depth) 213: { 214: child = tid.pageno; 215: tid.pageno = tid.page.parent; 216: parentkey(child, &tid); 217: for (i = tid.offset - 1; i >= 0; l += tid.page.node.intnode.key[i--]) 218: continue; 219: } 220: lid[tid.page.depth - 1] = l; 221: # ifdef xATR1 222: if (tTf(24,0)) 223: printf("lid=%ld\n", lid[tid.page.depth - 1]); 224: # endif 225: bmove(&tid.page.prttree, tidloc, LIDSIZE); 226: } while (tid.page.depth > 1); 227: } 228: 229: /* 230: ** Uses the secondary btree relation to find the btree tid corresponding 231: ** to a given main relation tid 232: */ 233: 234: search_btree(mtid, tidloc) 235: 236: TID mtid; 237: register TID *tidloc; 238: { 239: char key[2 * LIDSIZE], tup[2 * LIDSIZE]; 240: TID tid; 241: extern DESC Btreesec; 242: 243: # ifdef xATR1 244: if (tTf(24,0)) 245: { 246: printf("In Search_btree: searching for tid %ld\n", mtid); 247: printdesc(&Btreesec); 248: } 249: # endif 250: clearkeys(&Btreesec); 251: setkey(&Btreesec, key, &mtid, 1); 252: if (!getequal(&Btreesec, key, tup, &tid)) 253: bmove(tup + LIDSIZE, tidloc, LIDSIZE); 254: else 255: syserr("search_btree:can't find mtid %ld in btree", mtid); 256: # ifdef xATR1 257: if (tTf(24,0)) 258: printup(&Btreesec, tup); 259: # endif 260: } 261: 262: /* 263: ** Linearly searches the leaves of the BTree for a desired tid 264: ** 265: ** Parameters : 266: ** tree - BTree file name (I) 267: ** tid - desired tid value (I) 268: ** tidloc - location of the desired tid (O) 269: */ 270: 271: lin_search(level, tid, tidloc, lid, tupcnt) 272: 273: int level; 274: long tid; 275: TID *tidloc; 276: long lid[]; 277: long tupcnt; 278: { 279: struct locator block; 280: register int i; 281: long page, t, next; 282: int found; 283: long nextpage, count; 284: int forward, first; 285: 286: page = RT; 287: for (i = 0; i < level - 1; ++i) 288: { 289: t = get_tid(page, lid[i], &block); 290: page = t; 291: } 292: 293: found = 0; 294: forward = 0; 295: first = 1; 296: do 297: { 298: if (!forward) 299: { 300: get_node(page, &block.page); 301: next = block.page.nexttree; 302: } 303: count = 0; 304: 305: /* start at leftmost leaf */ 306: do 307: { 308: get_node(page, &block.page); 309: if (forward) 310: nextpage = block.page.nexttree; 311: else 312: nextpage = block.page.prevtree; 313: get_tid(page, 1, &block); 314: for ( ; ; ) 315: { 316: /* search through leaf */ 317: for (i = 0; i < block.page.nelmts && block.page.node.leafnode.tid_pos[block.page.node.leafnode.tid_loc[i]] != tid; ++i) 318: { 319: if (!first) 320: ++count; 321: } 322: if (i < block.page.nelmts && block.page.node.leafnode.tid_pos[block.page.node.leafnode.tid_loc[i]] == tid) 323: { 324: found = 1; 325: break; /* tid found */ 326: } 327: first = 0; 328: if (!(block.pageno = block.page.node.leafnode.nextleaf) || count >= tupcnt) 329: break; /* all leaves exhausted */ 330: else 331: /* try leaf to the right */ 332: get_node(block.pageno, &block.page); 333: } 334: if (found || count >= tupcnt) 335: break; 336: } while (page = nextpage); 337: nextpage = next; 338: forward = !forward; 339: } while (forward != 0 && !found); 340: if (!found) 341: syserr("search_btree: tid not found %ld", tid); 342: else 343: { 344: stuff_page(tidloc, &block.pageno); 345: tidloc->line_id = block.page.node.leafnode.tid_loc[i]; 346: } 347: } 348: 349: /* 350: ** Determines the value corresponding to the very last lid in the 351: ** BTree. 352: ** 353: ** Parameters : 354: ** tree - BTree file name (I) 355: ** 356: ** Returns : 357: ** value of last lid 358: */ 359: long 360: last_lid(rootpage) 361: 362: long rootpage; 363: 364: { 365: register int i; 366: long lid; 367: struct BTreeNode root; 368: 369: lid = 0; 370: get_node(rootpage, &root); 371: if (root.nodetype == 'L') 372: lid = root.nelmts; 373: else 374: for (i = 0; i < root.nelmts; ++i) 375: lid += root.node.intnode.key[i]; 376: ++lid; 377: return(lid); 378: } 379: 380: /* 381: ** Changes the tid value stored in the leaf of a BTree node 382: ** 383: ** Parameters : 384: ** tree - BTree file name (I) 385: ** tid - new tid value (I) 386: ** tidloc - location of tid to be replaced (I) 387: */ 388: 389: replace_btree(tid, tidloc) 390: 391: long tid; 392: register TID *tidloc; 393: 394: { 395: long pageno; 396: struct BTreeNode p; 397: 398: pluck_page(tidloc, &pageno); 399: get_node(pageno, &p); 400: p.node.leafnode.tid_pos[tidloc->line_id] = tid; 401: write_node(pageno, &p); 402: }