1: /* putnode -- store node and link structrures temporarily in a disk file */ 2: 3: #include "def.h" 4: #ifdef TMPFILES 5: /* 6: * Sizes of node and link caches. These must be big enough to prevent entries 7: * being flushed during assignments (e.g. getlink(l)->l_to = function(x), 8: * where function(x) pulls more than LINKCACHE entries into the cache). This 9: * is because the left hand side of the assignment is evaluated first and 10: * subsequent evaluation of the right hand side may replace the contents of 11: * the address being written into by a more recently used link (at least in 12: * Ritchie's compiler). This causes obscure errors. Avoid assignments of 13: * this type if the function makes lots of calls to getlink() or getnode(). 14: * Ten is certainly big enough, but hardly optimal. If you need more memory, 15: * shrink the hash table in addnode.c, don't change these. 16: */ 17: #define NODECACHE 35 /* tradeoff between user and sys time */ 18: #define LINKCACHE 35 19: 20: /* 21: * Linked lists and other miscellaneous cache debris. 22: */ 23: static struct nodecache { 24: struct nodecache *next; 25: struct nodecache *prev; 26: struct node node; 27: } nodecache[NODECACHE]; 28: 29: static struct linkcache { 30: struct linkcache *next; 31: struct linkcache *prev; 32: struct link link; 33: } linkcache[LINKCACHE]; 34: 35: static struct nodecache *topnode; 36: static struct linkcache *toplink; 37: 38: /* 39: * We set up offsets of zero to map to NULL for simplicity. 40: */ 41: node nullnode; 42: link nulllink; 43: 44: /* exports */ 45: void initstruct(); 46: extern node *getnode(); 47: extern link *getlink(); 48: char *nfile, *lfile, *sfile; 49: int fdnode, fdlink, fdname; 50: long nhits, lhits, nmisses, lmisses; 51: 52: /* imports */ 53: extern void nomem(), die(); 54: char *mktemp(); 55: off_t lseek(); 56: 57: /* privates */ 58: STATIC void nodewrite(), noderead(), linkwrite(), linkread(); 59: 60: /* 61: * Opens and initializes temporary files and caches. 62: */ 63: void 64: initstruct() 65: { 66: register int i; 67: 68: /* Open the temporary files. */ 69: nfile = mktemp("/tmp/nodeXXXXXX"); 70: if ((fdnode = open(nfile, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0) { 71: perror(nfile); 72: exit(1); 73: } 74: lfile = mktemp("/tmp/linkXXXXXX"); 75: if ((fdlink = open(lfile, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0) { 76: perror(lfile); 77: exit(1); 78: } 79: sfile = mktemp("/tmp/nameXXXXXX"); 80: if ((fdname = open(sfile, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0) { 81: perror(sfile); 82: exit(1); 83: } 84: 85: /* Put the handy null nodes, etc. at offset zero. */ 86: (void) write(fdnode, (char *) &nullnode, sizeof(nullnode)); 87: (void) write(fdlink, (char *) &nulllink, sizeof(nulllink)); 88: (void) write(fdname, "\0", 1); 89: 90: /* Link the caches together. */ 91: topnode = &nodecache[0]; 92: topnode->prev = (struct nodecache *) NULL; 93: topnode->next = &nodecache[1]; 94: for (i = 1; i < NODECACHE - 1; i++) { 95: nodecache[i].next = &nodecache[i+1]; 96: nodecache[i].prev = &nodecache[i-1]; 97: } 98: nodecache[NODECACHE - 1].prev = &nodecache[NODECACHE - 2]; 99: nodecache[NODECACHE - 1].next = (struct nodecache *) NULL; 100: 101: toplink = &linkcache[0]; 102: toplink->prev = (struct linkcache *) NULL; 103: toplink->next = &linkcache[1]; 104: for (i = 1; i < LINKCACHE - 1; i++) { 105: linkcache[i].next = &linkcache[i+1]; 106: linkcache[i].prev = &linkcache[i-1]; 107: } 108: linkcache[LINKCACHE - 1].prev = &linkcache[LINKCACHE - 2]; 109: linkcache[LINKCACHE - 1].next = (struct linkcache *) NULL; 110: } 111: 112: /* 113: * Returns pointer to node; takes sequence number of node. 114: */ 115: node * 116: getnode(n_seq) 117: register p_node n_seq; 118: { 119: register struct nodecache *tnode; 120: 121: /* Don't bother to retrieve the null entry. */ 122: if (n_seq == 0) 123: return((node *) NULL); 124: 125: /* 126: * First search for the correct entry in the cache. If we find it, 127: * move it to the top of the cache. 128: */ 129: for (tnode = topnode; tnode->next; tnode = tnode->next) { 130: if (n_seq == tnode->node.n_seq) { 131: found: if (tnode->prev) { 132: tnode->prev->next = tnode->next; 133: if (tnode->next) 134: tnode->next->prev = tnode->prev; 135: tnode->prev = (struct nodecache *) NULL; 136: tnode->next = topnode; 137: topnode->prev = tnode; 138: topnode = tnode; 139: } 140: nhits++; 141: return(&tnode->node); 142: } 143: } 144: if (n_seq == tnode->node.n_seq) 145: goto found; 146: 147: /* 148: * If it isn't in the cache, see if the last one in the 149: * cache has valid data. If it does, write it out, free 150: * the name pointer, fill it with the data we want, and 151: * move it to the top of the cache. 152: */ 153: if (tnode->node.n_seq) 154: nodewrite(&tnode->node); 155: if (tnode->node.n_name) 156: free((char *) tnode->node.n_name); 157: tnode->prev->next = (struct nodecache *) NULL; 158: tnode->prev = (struct nodecache *) NULL; 159: tnode->next = topnode; 160: topnode->prev = tnode; 161: topnode = tnode; 162: 163: noderead(&tnode->node, n_seq); 164: 165: nmisses++; 166: return(&tnode->node); 167: } 168: 169: /* 170: * Write out a node in cache to disk. Takes a pointer to the node to be 171: * written. If the name of the node hasn't ever been written to disk (as 172: * will be the case with new nodes), n_fname will be null; we fill it in and 173: * write the name to the name temporary file. 174: */ 175: STATIC void 176: nodewrite(n) 177: node *n; 178: { 179: if (n->n_fname == 0) { 180: n->n_fname = lseek(fdname, (off_t) 0, L_XTND); 181: if (write(fdname, n->n_name, strlen(n->n_name) + 1) < 0) { 182: perror("writename"); 183: exit(1); 184: } 185: } 186: (void) lseek(fdnode, (off_t) n->n_seq * sizeof(node), L_SET); 187: if (write(fdnode, (char *) n, sizeof(node)) < 0) { 188: perror("nodewrite"); 189: exit(1); 190: } 191: } 192: 193: /* 194: * Read a node from the disk into the cache. Takes the sequence number of the 195: * node to be read. We first read in the node, then set and fill in the 196: * pointer to the name of the node. 197: */ 198: STATIC void 199: noderead(n, n_seq) 200: node *n; 201: p_node n_seq; 202: { 203: (void) lseek(fdnode, (off_t) n_seq * sizeof(node), L_SET); 204: if (read(fdnode, (char *) n, sizeof(node)) < 0) { 205: perror("noderead"); 206: exit(1); 207: } 208: if (n->n_fname) { 209: if ((n->n_name = calloc(1, MAXNAME + 1)) == 0) 210: nomem(); 211: (void) lseek(fdname, n->n_fname, L_SET); 212: if (read(fdname, n->n_name, MAXNAME + 1) < 0) { 213: perror("readname"); 214: exit(1); 215: } 216: } 217: if (n->n_seq && n->n_seq != n_seq) { /* sanity check */ 218: fprintf(stderr, "noderead %u gives %u\n", n_seq, n->n_seq); 219: die("impossible retrieval error"); 220: } 221: } 222: 223: /* 224: * Returns pointer to link; takes sequence number of link. 225: */ 226: link * 227: getlink(l_seq) 228: register p_link l_seq; 229: { 230: register struct linkcache *tlink; 231: 232: /* Don't bother to retrieve the null entry. */ 233: if (l_seq == 0) 234: return((link *) NULL); 235: 236: /* 237: * First search for the correct entry in the cache. If we find it, 238: * move it to the top of the cache. 239: */ 240: for (tlink = toplink; tlink->next; tlink = tlink->next) { 241: if (l_seq == tlink->link.l_seq) { 242: found: if (tlink->prev) { 243: tlink->prev->next = tlink->next; 244: if (tlink->next) 245: tlink->next->prev = tlink->prev; 246: tlink->prev = (struct linkcache *) NULL; 247: tlink->next = toplink; 248: toplink->prev = tlink; 249: toplink = tlink; 250: } 251: lhits++; 252: return(&tlink->link); 253: } 254: } 255: if (l_seq == tlink->link.l_seq) 256: goto found; 257: 258: /* 259: * If it isn't in the cache, see if the last one in the cache has 260: * valid data. If it does, write it out, fill it with the data we 261: * want, and move it to the top of the cache. 262: */ 263: if (tlink->link.l_seq) 264: linkwrite(&tlink->link); 265: tlink->prev->next = (struct linkcache *) NULL; 266: tlink->prev = (struct linkcache *) NULL; 267: tlink->next = toplink; 268: toplink->prev = tlink; 269: toplink = tlink; 270: 271: linkread(&tlink->link, l_seq); 272: 273: lmisses++; 274: return(&tlink->link); 275: } 276: 277: /* 278: * Write out a link in cache to disk. Takes a pointer to the link to be 279: * written. 280: */ 281: STATIC void 282: linkwrite(l) 283: link *l; 284: { 285: (void) lseek(fdlink, (off_t) l->l_seq * sizeof(link), L_SET); 286: if (write(fdlink, (char *) l, sizeof(link)) < 0) { 287: perror("linkwrite"); 288: exit(1); 289: } 290: } 291: 292: /* 293: * Read a link from the disk into the cache. Takes the sequence number of the 294: * link to be read. 295: */ 296: STATIC void 297: linkread(l, l_seq) 298: link *l; 299: p_link l_seq; 300: { 301: (void) lseek(fdlink, (off_t) l_seq * sizeof(link), L_SET); 302: if (read(fdlink, (char *) l, sizeof(link)) < 0) { 303: perror("linkread"); 304: exit(1); 305: } 306: } 307: #endif /*TMPFILES*/