ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/holofile.c
Revision: 3.42
Committed: Sat Feb 22 02:07:24 2003 UTC (21 years, 1 month ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad3R5
Changes since 3.41: +20 -23 lines
Log Message:
Changes and check-in for 3.5 release
Includes new source files and modifications not recorded for many years
See ray/doc/notes/ReleaseNotes for notes between 3.1 and 3.5 release

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id$";
3 #endif
4 /*
5 * Routines for managing holodeck files
6 *
7 * 9/30/97 GWLarson
8 */
9
10 #include "holo.h"
11
12 #ifndef CACHESIZE
13 #ifdef BIGMEM
14 #define CACHESIZE 17 /* default cache size (Mbytes, 0==inf) */
15 #else
16 #define CACHESIZE 5
17 #endif
18 #endif
19 #ifndef FREEBEAMS
20 #define FREEBEAMS 1500 /* maximum beams to free at a time */
21 #endif
22 #ifndef PCTFREE
23 #define PCTFREE 15 /* maximum fraction to free (%) */
24 #endif
25 #ifndef MAXFRAGB
26 #define MAXFRAGB 16 /* fragment blocks/file to track (0==inf) */
27 #endif
28 #ifndef FF_DEFAULT
29 /* when to free a beam fragment */
30 #define FF_DEFAULT (FF_WRITE|FF_KILL)
31 #endif
32 #ifndef MINDIRSEL
33 /* minimum directory seek length */
34 #define MINDIRSEL (4*BUFSIZ/sizeof(BEAMI))
35 #endif
36
37 #ifndef BSD
38 #define write writebuf /* safe i/o routines */
39 #define read readbuf
40 #endif
41
42 #define FRAGBLK 512 /* number of fragments to allocate at a time */
43
44 int hdfragflags = FF_DEFAULT; /* tells when to free fragments */
45 unsigned hdcachesize = CACHESIZE*1024*1024; /* target cache size */
46 unsigned long hdclock; /* clock value */
47
48 HOLO *hdlist[HDMAX+1]; /* holodeck pointers (NULL term.) */
49
50 static struct fraglist {
51 short nlinks; /* number of holodeck sections using us */
52 short writable; /* 0 read-only, <0 write error encountered */
53 int nfrags; /* number of known fragments */
54 BEAMI *fi; /* fragments, descending file position */
55 long flen; /* last known file length */
56 } *hdfragl; /* fragment lists, indexed by file descriptor */
57
58 static int nhdfragls; /* size of hdfragl array */
59
60
61 HOLO *
62 hdalloc(hproto) /* allocate and set holodeck section based on grid */
63 HDGRID *hproto;
64 {
65 HOLO hdhead;
66 register HOLO *hp;
67 int n;
68 /* copy grid to temporary header */
69 bcopy((char *)hproto, (char *)&hdhead, sizeof(HDGRID));
70 /* compute grid vectors and sizes */
71 hdcompgrid(&hdhead);
72 /* allocate header with directory */
73 n = sizeof(HOLO)+nbeams(&hdhead)*sizeof(BEAMI);
74 if ((hp = (HOLO *)malloc(n)) == NULL)
75 return(NULL);
76 /* copy header information */
77 copystruct(hp, &hdhead);
78 /* allocate and clear beam list */
79 hp->bl = (BEAM **)malloc((nbeams(hp)+1)*sizeof(BEAM *)+sizeof(BEAM));
80 if (hp->bl == NULL) {
81 free((void *)hp);
82 return(NULL);
83 }
84 bzero((char *)hp->bl, (nbeams(hp)+1)*sizeof(BEAM *)+sizeof(BEAM));
85 hp->bl[0] = (BEAM *)(hp->bl+nbeams(hp)+1); /* set blglob(hp) */
86 hp->fd = -1;
87 hp->dirty = 0;
88 hp->priv = NULL;
89 /* clear beam directory */
90 bzero((char *)hp->bi, (nbeams(hp)+1)*sizeof(BEAMI));
91 return(hp); /* all is well */
92 }
93
94
95 char *
96 hdrealloc(ptr, siz, rout) /* (re)allocate memory, retry then error */
97 char *ptr;
98 unsigned siz;
99 char *rout;
100 {
101 register char *newp;
102 /* call malloc/realloc */
103 if (ptr == NULL) newp = (char *)malloc(siz);
104 else newp = (char *)realloc(ptr, siz);
105 /* check success */
106 if (newp == NULL && rout != NULL) {
107 hdfreecache(25, NULL); /* free some memory */
108 errno = 0; /* retry */
109 newp = hdrealloc(ptr, siz, NULL);
110 if (newp == NULL) { /* give up and report error */
111 sprintf(errmsg, "out of memory in %s", rout);
112 error(SYSTEM, errmsg);
113 }
114 }
115 return(newp);
116 }
117
118
119 hdattach(fd, wr) /* start tracking file fragments for some section */
120 register int fd;
121 int wr;
122 {
123 if (fd >= nhdfragls) {
124 hdfragl = (struct fraglist *)hdrealloc((char *)hdfragl,
125 (fd+1)*sizeof(struct fraglist), "hdattach");
126 bzero((char *)(hdfragl+nhdfragls),
127 (fd+1-nhdfragls)*sizeof(struct fraglist));
128 nhdfragls = fd+1;
129 }
130 hdfragl[fd].nlinks++;
131 hdfragl[fd].writable = wr; /* set writable flag */
132 hdfragl[fd].flen = lseek(fd, (off_t)0L, 2); /* get file length */
133 }
134
135
136 /* Do we need a routine to locate file fragments given known occupants? */
137
138
139 hdrelease(fd) /* stop tracking file fragments for some section */
140 register int fd;
141 {
142 if (fd < 0 | fd >= nhdfragls || !hdfragl[fd].nlinks)
143 return;
144 if (!--hdfragl[fd].nlinks && hdfragl[fd].nfrags) {
145 free((void *)hdfragl[fd].fi);
146 hdfragl[fd].fi = NULL;
147 hdfragl[fd].nfrags = 0;
148 }
149 }
150
151
152 HOLO *
153 hdinit(fd, hproto) /* initialize a holodeck section in a file */
154 int fd; /* corresponding file descriptor */
155 HDGRID *hproto; /* holodeck section grid */
156 {
157 long rtrunc;
158 long fpos;
159 int writable;
160 register HOLO *hp;
161 register int n;
162 /* prepare for system errors */
163 errno = 0;
164 if ((fpos = lseek(fd, (off_t)0L, 1)) < 0)
165 error(SYSTEM, "cannot determine holodeck file position");
166 if (hproto == NULL) { /* assume we're loading it */
167 HDGRID hpr;
168 /* load header */
169 if (read(fd, (char *)&hpr, sizeof(HDGRID)) != sizeof(HDGRID))
170 error(SYSTEM, "cannot load holodeck header");
171 /* allocate grid */
172 if ((hp = hdalloc(&hpr)) == NULL)
173 goto memerr;
174 /* load beam directory */
175 n = nbeams(hp)*sizeof(BEAMI);
176 if (read(fd, (char *)(hp->bi+1), n) != n)
177 error(SYSTEM, "failure loading holodeck directory");
178 /* check that it's clean */
179 for (n = nbeams(hp); n > 0; n--)
180 if (hp->bi[n].fo < 0) {
181 hp->bi[n].fo = 0;
182 error(WARNING, "dirty holodeck section");
183 break;
184 }
185 /* check writability */
186 if (fd < nhdfragls && hdfragl[fd].nlinks)
187 writable = hdfragl[fd].writable;
188 else
189 writable = lseek(fd, (off_t)fpos, 0) == fpos &&
190 write(fd, (char *)hp, sizeof(HDGRID)) ==
191 sizeof(HDGRID);
192 } else { /* else assume we're creating it */
193 if ((hp = hdalloc(hproto)) == NULL)
194 goto memerr;
195 /* write header and skeleton */
196 n = nbeams(hp)*sizeof(BEAMI);
197 if (write(fd, (char *)hproto, sizeof(HDGRID)) !=
198 sizeof(HDGRID) ||
199 write(fd, (char *)(hp->bi+1), n) != n)
200 error(SYSTEM, "cannot write header to holodeck file");
201 writable = 1;
202 }
203 hp->fd = fd;
204 hp->dirty = 0;
205 biglob(hp)->fo = fpos + sizeof(HDGRID);
206 /* start tracking fragments */
207 hdattach(fd, writable);
208 /* check rays on disk */
209 fpos = hdfilen(fd);
210 biglob(hp)->nrd = rtrunc = 0;
211 for (n = hproto == NULL ? nbeams(hp) : 0; n > 0; n--)
212 if (hp->bi[n].nrd)
213 if (hp->bi[n].fo+hp->bi[n].nrd*sizeof(RAYVAL) > fpos) {
214 rtrunc += hp->bi[n].nrd;
215 hp->bi[n].nrd = 0;
216 } else
217 biglob(hp)->nrd += hp->bi[n].nrd;
218 if (rtrunc) {
219 sprintf(errmsg, "truncated section, %ld rays lost (%.1f%%)",
220 rtrunc, 100.*rtrunc/(rtrunc+biglob(hp)->nrd));
221 error(WARNING, errmsg);
222 }
223 /* add to holodeck list */
224 for (n = 0; n < HDMAX; n++)
225 if (hdlist[n] == NULL) {
226 hdlist[n] = hp;
227 break;
228 }
229 /* all done */
230 return(hp);
231 memerr:
232 error(SYSTEM, "cannot allocate holodeck grid");
233 }
234
235
236 hdmarkdirty(hp, i) /* mark holodeck directory position dirty */
237 register HOLO *hp;
238 int i;
239 {
240 static BEAMI smudge = {0, -1};
241 int mindist, minpos;
242 register int j;
243
244 if (!hp->dirty++) { /* write smudge first time */
245 if (lseek(hp->fd, (off_t)(biglob(hp)->fo+(i-1)*sizeof(BEAMI)), 0) < 0
246 || write(hp->fd, (char *)&smudge,
247 sizeof(BEAMI)) != sizeof(BEAMI))
248 error(SYSTEM, "seek/write error in hdmarkdirty");
249 hp->dirseg[0].s = i;
250 hp->dirseg[0].n = 1;
251 return;
252 }
253 /* insert into segment list */
254 for (j = hp->dirty; j--; ) {
255 if (!j || hp->dirseg[j-1].s < i) {
256 hp->dirseg[j].s = i;
257 hp->dirseg[j].n = 1;
258 break;
259 }
260 copystruct(hp->dirseg+j, hp->dirseg+(j-1));
261 }
262 do { /* check neighbors */
263 mindist = nbeams(hp); /* find closest */
264 for (j = hp->dirty; --j; )
265 if (hp->dirseg[j].s -
266 (hp->dirseg[j-1].s + hp->dirseg[j-1].n)
267 < mindist) {
268 minpos = j;
269 mindist = hp->dirseg[j].s -
270 (hp->dirseg[j-1].s + hp->dirseg[j-1].n);
271 }
272 /* good enough? */
273 if (hp->dirty <= MAXDIRSE && mindist > MINDIRSEL)
274 break;
275 j = minpos - 1; /* coalesce neighbors */
276 if (hp->dirseg[j].s + hp->dirseg[j].n <
277 hp->dirseg[minpos].s + hp->dirseg[minpos].n)
278 hp->dirseg[j].n = hp->dirseg[minpos].s +
279 hp->dirseg[minpos].n - hp->dirseg[j].s;
280 hp->dirty--;
281 while (++j < hp->dirty) /* close the gap */
282 copystruct(hp->dirseg+j, hp->dirseg+(j+1));
283 } while (mindist <= MINDIRSEL);
284 }
285
286
287 int
288 hdsync(hp, all) /* update beams and directory on disk */
289 register HOLO *hp;
290 int all;
291 {
292 register int j, n;
293
294 if (hp == NULL) { /* do all holodecks */
295 n = 0;
296 for (j = 0; hdlist[j] != NULL; j++)
297 n += hdsync(hdlist[j], all);
298 return(n);
299 }
300 /* sync the beams */
301 for (j = (all ? nbeams(hp) : 0); j > 0; j--)
302 if (hp->bl[j] != NULL)
303 hdsyncbeam(hp, j);
304 if (!hp->dirty) /* directory clean? */
305 return(0);
306 errno = 0; /* write dirty segments */
307 for (j = 0; j < hp->dirty; j++) {
308 if (lseek(hp->fd, (off_t)(biglob(hp)->fo +
309 (hp->dirseg[j].s-1)*sizeof(BEAMI)), 0) < 0)
310 error(SYSTEM, "cannot seek on holodeck file");
311 n = hp->dirseg[j].n * sizeof(BEAMI);
312 if (write(hp->fd, (char *)(hp->bi+hp->dirseg[j].s), n) != n)
313 error(SYSTEM, "cannot update section directory");
314 }
315 hp->dirty = 0; /* all clean */
316 return(1);
317 }
318
319
320 unsigned
321 hdmemuse(all) /* return memory usage (in bytes) */
322 int all; /* include overhead (painful) */
323 {
324 long total = 0;
325 register int i, j;
326
327 for (j = 0; hdlist[j] != NULL; j++) {
328 total += blglob(hdlist[j])->nrm * sizeof(RAYVAL);
329 if (all) {
330 total += sizeof(HOLO) + sizeof(BEAM *) +
331 nbeams(hdlist[j]) *
332 (sizeof(BEAM *)+sizeof(BEAMI));
333 for (i = nbeams(hdlist[j]); i > 0; i--)
334 if (hdlist[j]->bl[i] != NULL)
335 total += sizeof(BEAM);
336 }
337 }
338 if (all)
339 for (j = 0; j < nhdfragls; j++) {
340 total += sizeof(struct fraglist);
341 if (hdfragl[j].nfrags)
342 total += FRAGBLK*sizeof(BEAMI) *
343 ((hdfragl[j].nfrags-1)/FRAGBLK + 1) ;
344 }
345 return(total);
346 }
347
348
349 long
350 hdfilen(fd) /* return file length for fd */
351 int fd;
352 {
353 long fpos, flen;
354
355 if (fd < 0)
356 return(-1);
357 if (fd >= nhdfragls || !hdfragl[fd].nlinks) {
358 if ((fpos = lseek(fd, (off_t)0L, 1)) < 0)
359 return(-1);
360 flen = lseek(fd, (off_t)0L, 2);
361 lseek(fd, (off_t)fpos, 0);
362 return(flen);
363 }
364 return(hdfragl[fd].flen);
365 }
366
367
368 long
369 hdfiluse(fd, all) /* compute file usage (in bytes) */
370 int fd; /* open file descriptor to check */
371 int all; /* include overhead and unflushed data */
372 {
373 long total = 0;
374 register int i, j;
375
376 for (j = 0; hdlist[j] != NULL; j++) {
377 if (hdlist[j]->fd != fd)
378 continue;
379 total += biglob(hdlist[j])->nrd * sizeof(RAYVAL);
380 if (all) {
381 for (i = nbeams(hdlist[j]); i > 0; i--)
382 if (hdlist[j]->bl[i] != NULL)
383 total += sizeof(RAYVAL) *
384 (hdlist[j]->bl[i]->nrm -
385 hdlist[j]->bi[i].nrd);
386 total += sizeof(HDGRID) +
387 nbeams(hdlist[j])*sizeof(BEAMI);
388 }
389 }
390 return(total); /* does not include fragments */
391 }
392
393
394 RAYVAL *
395 hdnewrays(hp, i, nr) /* allocate space for add'l rays and return pointer */
396 register HOLO *hp;
397 register int i;
398 int nr; /* number of new rays desired */
399 {
400 RAYVAL *p;
401 int n;
402
403 if (nr <= 0) return(NULL);
404 CHECK(i < 1 | i > nbeams(hp),
405 CONSISTENCY, "bad beam index given to hdnewrays");
406 if (hp->bl[i] != NULL)
407 hp->bl[i]->tick = hdclock; /* preempt swap */
408 if (hdcachesize > 0 && hdmemuse(0) >= hdcachesize)
409 hdfreecache(PCTFREE, NULL); /* free some space */
410 if (hp->bl[i] == NULL) { /* allocate (and load) */
411 n = hp->bi[i].nrd + nr;
412 hp->bl[i] = (BEAM *)hdrealloc(NULL, hdbsiz(n), "hdnewrays");
413 blglob(hp)->nrm += n;
414 if ((n = hp->bl[i]->nrm = hp->bi[i].nrd)) {
415 errno = 0;
416 if (lseek(hp->fd, (off_t)hp->bi[i].fo, 0) < 0)
417 error(SYSTEM, "seek error on holodeck file");
418 n *= sizeof(RAYVAL);
419 if (read(hp->fd, (char *)hdbray(hp->bl[i]), n) != n)
420 error(SYSTEM,
421 "error reading beam from holodeck file");
422 }
423 } else { /* just grow in memory */
424 hp->bl[i] = (BEAM *)hdrealloc((char *)hp->bl[i],
425 hdbsiz(hp->bl[i]->nrm + nr), "hdnewrays");
426 blglob(hp)->nrm += nr;
427 }
428 if (hdfragflags&FF_ALLOC && hp->bi[i].nrd)
429 hdfreefrag(hp, i); /* relinquish old fragment */
430 p = hdbray(hp->bl[i]) + hp->bl[i]->nrm;
431 hp->bl[i]->nrm += nr; /* update in-core structure */
432 bzero((char *)p, nr*sizeof(RAYVAL));
433 blglob(hp)->tick = hp->bl[i]->tick = hdclock++; /* update LRU clock */
434 return(p); /* point to new rays */
435 }
436
437
438 BEAM *
439 hdgetbeam(hp, i) /* get beam (from file if necessary) */
440 register HOLO *hp;
441 register int i;
442 {
443 register int n;
444
445 CHECK(i < 1 | i > nbeams(hp),
446 CONSISTENCY, "bad beam index given to hdgetbeam");
447 if (hp->bl[i] == NULL) { /* load from disk */
448 if (!(n = hp->bi[i].nrd))
449 return(NULL);
450 if (hdcachesize > 0 && hdmemuse(0) >= hdcachesize)
451 hdfreecache(PCTFREE, NULL); /* get free space */
452 hp->bl[i] = (BEAM *)hdrealloc(NULL, hdbsiz(n), "hdgetbeam");
453 blglob(hp)->nrm += hp->bl[i]->nrm = n;
454 errno = 0;
455 if (lseek(hp->fd, (off_t)hp->bi[i].fo, 0) < 0)
456 error(SYSTEM, "seek error on holodeck file");
457 n *= sizeof(RAYVAL);
458 if (read(hp->fd, (char *)hdbray(hp->bl[i]), n) != n)
459 error(SYSTEM, "error reading beam from holodeck file");
460 if (hdfragflags&FF_READ)
461 hdfreefrag(hp, i); /* relinquish old frag. */
462 }
463 blglob(hp)->tick = hp->bl[i]->tick = hdclock++; /* update LRU clock */
464 return(hp->bl[i]);
465 }
466
467
468 int
469 hdfilord(hb1, hb2) /* order beams for quick loading */
470 register HDBEAMI *hb1, *hb2;
471 {
472 register long c;
473 /* residents go first */
474 if (hb2->h->bl[hb2->b] != NULL)
475 return(hb1->h->bl[hb1->b] == NULL);
476 if (hb1->h->bl[hb1->b] != NULL)
477 return(-1);
478 /* otherwise sort by file descriptor */
479 if ((c = hb1->h->fd - hb2->h->fd))
480 return(c);
481 /* then by position in file */
482 c = hb1->h->bi[hb1->b].fo - hb2->h->bi[hb2->b].fo;
483 return(c > 0 ? 1 : c < 0 ? -1 : 0);
484 }
485
486
487 hdloadbeams(hb, n, bf) /* load a list of beams in optimal order */
488 register HDBEAMI *hb; /* list gets sorted by hdfilord() */
489 int n; /* list length */
490 int (*bf)(); /* callback function (optional) */
491 {
492 unsigned origcachesize, memuse;
493 int bytesloaded, needbytes, bytes2free;
494 register BEAM *bp;
495 register int i;
496 /* precheck consistency */
497 if (n <= 0) return;
498 for (i = n; i--; )
499 if (hb[i].h==NULL || hb[i].b<1 | hb[i].b>nbeams(hb[i].h))
500 error(CONSISTENCY, "bad beam in hdloadbeams");
501 /* sort list for optimal access */
502 qsort((char *)hb, n, sizeof(HDBEAMI), hdfilord);
503 bytesloaded = 0; /* run through loaded beams */
504 for ( ; n && (bp = hb->h->bl[hb->b]) != NULL; n--, hb++) {
505 bp->tick = hdclock; /* preempt swap */
506 bytesloaded += bp->nrm;
507 if (bf != NULL)
508 (*bf)(bp, hb);
509 }
510 bytesloaded *= sizeof(RAYVAL);
511 if ((origcachesize = hdcachesize) > 0) {
512 needbytes = 0; /* figure out memory needs */
513 for (i = n; i--; )
514 needbytes += hb[i].h->bi[hb[i].b].nrd;
515 needbytes *= sizeof(RAYVAL);
516 do { /* free enough memory */
517 memuse = hdmemuse(0);
518 bytes2free = needbytes - (int)(hdcachesize-memuse);
519 if (bytes2free > (int)(memuse - bytesloaded))
520 bytes2free = memuse - bytesloaded;
521 } while (bytes2free > 0 &&
522 hdfreecache(100*bytes2free/memuse, NULL) < 0);
523 hdcachesize = 0; /* load beams w/o swap */
524 }
525 for (i = 0; i < n; i++)
526 if ((bp = hdgetbeam(hb[i].h, hb[i].b)) != NULL && bf != NULL)
527 (*bf)(bp, hb+i);
528 hdcachesize = origcachesize; /* resume dynamic swapping */
529 }
530
531
532 int
533 hdfreefrag(hp, i) /* free a file fragment */
534 HOLO *hp;
535 int i;
536 {
537 register BEAMI *bi = &hp->bi[i];
538 register struct fraglist *f;
539 register int j, k;
540
541 if (bi->nrd <= 0)
542 return(0);
543 DCHECK(hp->fd < 0 | hp->fd >= nhdfragls || !hdfragl[hp->fd].nlinks,
544 CONSISTENCY, "bad file descriptor in hdfreefrag");
545 f = &hdfragl[hp->fd];
546 if (!f->writable)
547 return(0);
548 if (f->nfrags % FRAGBLK == 0) { /* delete empty remnants */
549 for (j = k = 0; k < f->nfrags; j++, k++) {
550 while (f->fi[k].nrd == 0)
551 if (++k >= f->nfrags)
552 goto endloop;
553 if (k > j)
554 copystruct(f->fi+j, f->fi+k);
555 }
556 endloop:
557 f->nfrags = j;
558 }
559 j = f->nfrags++; /* allocate a slot in free list */
560 #if MAXFRAGB
561 if (j >= MAXFRAGB*FRAGBLK) {
562 f->nfrags = j--; /* stop list growth */
563 if (bi->nrd <= f->fi[j].nrd)
564 return(0); /* new one no better than discard */
565 }
566 #endif
567 if (j % FRAGBLK == 0) { /* more (or less) free list space */
568 register BEAMI *newp;
569 if (f->fi == NULL)
570 newp = (BEAMI *)malloc((j+FRAGBLK)*sizeof(BEAMI));
571 else
572 newp = (BEAMI *)realloc((char *)f->fi,
573 (j+FRAGBLK)*sizeof(BEAMI));
574 if (newp == NULL) {
575 f->nfrags--; /* graceful failure */
576 return(0);
577 }
578 f->fi = newp;
579 }
580 for ( ; ; j--) { /* insert in descending list */
581 if (!j || bi->fo < f->fi[j-1].fo) {
582 f->fi[j].fo = bi->fo;
583 f->fi[j].nrd = bi->nrd;
584 break;
585 }
586 copystruct(f->fi+j, f->fi+(j-1));
587 }
588 /* coalesce adjacent fragments */
589 /* successors never empty */
590 if (j && f->fi[j-1].fo == f->fi[j].fo + f->fi[j].nrd*sizeof(RAYVAL)) {
591 f->fi[j].nrd += f->fi[j-1].nrd;
592 f->fi[j-1].nrd = 0;
593 }
594 for (k = j+1; k < f->nfrags; k++) /* get non-empty predecessor */
595 if (f->fi[k].nrd) {
596 if (f->fi[j].fo == f->fi[k].fo +
597 f->fi[k].nrd*sizeof(RAYVAL)) {
598 f->fi[k].nrd += f->fi[j].nrd;
599 f->fi[j].nrd = 0;
600 }
601 break;
602 }
603 biglob(hp)->nrd -= bi->nrd; /* tell fragment it's free */
604 bi->nrd = 0;
605 bi->fo = 0L;
606 hdmarkdirty(hp, i); /* assume we'll reallocate */
607 return(1);
608 }
609
610
611 int
612 hdfragOK(fd, listlen, listsiz) /* get fragment list status for file */
613 int fd;
614 int *listlen;
615 register int4 *listsiz;
616 {
617 register struct fraglist *f;
618 register int i;
619
620 if (fd < 0 | fd >= nhdfragls || !(f = &hdfragl[fd])->nlinks)
621 return(0); /* listless */
622 if (listlen != NULL)
623 *listlen = f->nfrags;
624 if (listsiz != NULL)
625 for (i = f->nfrags, *listsiz = 0; i--; )
626 *listsiz += f->fi[i].nrd;
627 #if MAXFRAGB
628 return(f->nfrags < MAXFRAGB*FRAGBLK);
629 #else
630 return(1); /* list never fills up */
631 #endif
632 }
633
634
635 long
636 hdallocfrag(fd, nrays) /* allocate a file fragment */
637 int fd;
638 unsigned int4 nrays;
639 {
640 register struct fraglist *f;
641 register int j;
642 long nfo;
643
644 if (nrays == 0)
645 return(-1L);
646 DCHECK(fd < 0 | fd >= nhdfragls || !hdfragl[fd].nlinks,
647 CONSISTENCY, "bad file descriptor in hdallocfrag");
648 f = &hdfragl[fd];
649 for (j = f->nfrags; j-- > 0; ) /* first fit algorithm */
650 if (f->fi[j].nrd >= nrays)
651 break;
652 if (j < 0) { /* no fragment -- extend file */
653 nfo = f->flen;
654 f->flen += nrays*sizeof(RAYVAL);
655 } else { /* else use fragment */
656 nfo = f->fi[j].fo;
657 f->fi[j].fo += nrays*sizeof(RAYVAL);
658 f->fi[j].nrd -= nrays;
659 }
660 return(nfo);
661 }
662
663
664 int
665 hdsyncbeam(hp, i) /* sync beam in memory with beam on disk */
666 register HOLO *hp;
667 register int i;
668 {
669 int fragfreed;
670 unsigned int4 nrays;
671 unsigned int n;
672 long nfo;
673 /* check file status */
674 if (hdfragl[hp->fd].writable <= 0)
675 return(hdfragl[hp->fd].writable);
676 DCHECK(i < 1 | i > nbeams(hp),
677 CONSISTENCY, "bad beam index in hdsyncbeam");
678 /* is current fragment OK? */
679 if (hp->bl[i] == NULL || (nrays = hp->bl[i]->nrm) == hp->bi[i].nrd)
680 return(0);
681 /* relinquish old fragment? */
682 fragfreed = hdfragflags&FF_WRITE && hp->bi[i].nrd && hdfreefrag(hp,i);
683 if (nrays) { /* get and write new fragment */
684 nfo = hdallocfrag(hp->fd, nrays);
685 errno = 0;
686 if (lseek(hp->fd, (off_t)nfo, 0) < 0)
687 error(SYSTEM, "cannot seek on holodeck file");
688 n = hp->bl[i]->nrm * sizeof(RAYVAL);
689 if (write(hp->fd, (char *)hdbray(hp->bl[i]), n) != n) {
690 hdfragl[hp->fd].writable = -1;
691 hdsync(NULL, 0); /* sync directories */
692 error(SYSTEM, "write error in hdsyncbeam");
693 }
694 hp->bi[i].fo = nfo;
695 } else
696 hp->bi[i].fo = 0L;
697 biglob(hp)->nrd += nrays - hp->bi[i].nrd;
698 hp->bi[i].nrd = nrays;
699 if (!fragfreed)
700 hdmarkdirty(hp, i); /* need to flag dir. ent. */
701 return(1);
702 }
703
704
705 int
706 hdfreebeam(hp, i) /* free beam, writing if dirty */
707 register HOLO *hp;
708 register int i;
709 {
710 int nchanged;
711
712 if (hp == NULL) { /* clear all holodecks */
713 nchanged = 0;
714 for (i = 0; hdlist[i] != NULL; i++)
715 nchanged += hdfreebeam(hdlist[i], 0);
716 return(nchanged);
717 }
718 if (hdfragl[hp->fd].writable < 0) /* check for file error */
719 return(0);
720 if (i == 0) { /* clear entire holodeck */
721 if (blglob(hp)->nrm == 0)
722 return(0); /* already clear */
723 nchanged = 0;
724 for (i = nbeams(hp); i > 0; i--)
725 if (hp->bl[i] != NULL)
726 nchanged += hdfreebeam(hp, i);
727 DCHECK(blglob(hp)->nrm != 0,
728 CONSISTENCY, "bad beam count in hdfreebeam");
729 return(nchanged);
730 }
731 DCHECK(i < 1 | i > nbeams(hp),
732 CONSISTENCY, "bad beam index to hdfreebeam");
733 if (hp->bl[i] == NULL)
734 return(0);
735 /* check for additions */
736 nchanged = hp->bl[i]->nrm - hp->bi[i].nrd;
737 if (nchanged)
738 hdsyncbeam(hp, i); /* write new fragment */
739 blglob(hp)->nrm -= hp->bl[i]->nrm;
740 free((void *)hp->bl[i]); /* free memory */
741 hp->bl[i] = NULL;
742 return(nchanged);
743 }
744
745
746 int
747 hdkillbeam(hp, i) /* delete beam from holodeck */
748 register HOLO *hp;
749 register int i;
750 {
751 int nchanged;
752
753 if (hp == NULL) { /* clobber all holodecks */
754 nchanged = 0;
755 for (i = 0; hdlist[i] != NULL; i++)
756 nchanged += hdkillbeam(hdlist[i], 0);
757 return(nchanged);
758 }
759 if (i == 0) { /* clobber entire holodeck */
760 if (biglob(hp)->nrd == 0 & blglob(hp)->nrm == 0)
761 return(0); /* already empty */
762 nchanged = 0;
763 nchanged = 0;
764 for (i = nbeams(hp); i > 0; i--)
765 if (hp->bi[i].nrd > 0 || hp->bl[i] != NULL)
766 nchanged += hdkillbeam(hp, i);
767 DCHECK(biglob(hp)->nrd != 0 | blglob(hp)->nrm != 0,
768 CONSISTENCY, "bad beam count in hdkillbeam");
769 return(nchanged);
770 }
771 DCHECK(i < 1 | i > nbeams(hp), CONSISTENCY,
772 "bad beam index to hdkillbeam");
773 DCHECK(!hdfragl[hp->fd].writable, CONSISTENCY,
774 "hdkillbeam called on read-only holodeck");
775 if (hp->bl[i] != NULL) { /* free memory */
776 blglob(hp)->nrm -= nchanged = hp->bl[i]->nrm;
777 free((void *)hp->bl[i]);
778 hp->bl[i] = NULL;
779 } else
780 nchanged = hp->bi[i].nrd;
781 if (hp->bi[i].nrd && !(hdfragflags&FF_KILL && hdfreefrag(hp,i))) {
782 biglob(hp)->nrd -= hp->bi[i].nrd; /* free failed */
783 hp->bi[i].nrd = 0;
784 hp->bi[i].fo = 0L;
785 hdmarkdirty(hp, i);
786 }
787 return(nchanged);
788 }
789
790
791 int
792 hdlrulist(hb, nents, n, hp) /* add beams from holodeck to LRU list */
793 register HDBEAMI *hb; /* beam list */
794 int nents; /* current list length */
795 int n; /* maximum list length */
796 register HOLO *hp; /* section we're adding from */
797 {
798 register int i, j;
799 /* insert each beam from hp */
800 for (i = 1; i <= nbeams(hp); i++) {
801 if (hp->bl[i] == NULL) /* check if loaded */
802 continue;
803 #if 0
804 if (hp->bl[i]->tick == hdclock) /* preempt swap? */
805 continue;
806 #endif
807 if ((j = ++nents) >= n) /* grow list if we can */
808 nents--;
809 for ( ; ; ) { /* bubble into place */
810 if (!--j || hp->bl[i]->tick >=
811 hb[j-1].h->bl[hb[j-1].b]->tick) {
812 hb[j].h = hp;
813 hb[j].b = i;
814 break;
815 }
816 copystruct(hb+j, hb+(j-1));
817 }
818 }
819 return(nents); /* return new list length */
820 }
821
822
823 int
824 hdfreecache(pct, honly) /* free up cache space, writing changes */
825 int pct; /* maximum percentage to free */
826 register HOLO *honly; /* NULL means check all */
827 {
828 HDBEAMI hb[FREEBEAMS];
829 int freetarget;
830 int n;
831 register int i;
832 #ifdef DEBUG
833 unsigned membefore;
834
835 membefore = hdmemuse(0);
836 #endif
837 /* compute free target */
838 freetarget = (honly != NULL) ? blglob(honly)->nrm :
839 hdmemuse(0)/sizeof(RAYVAL) ;
840 freetarget = freetarget*pct/100;
841 if (freetarget <= 0)
842 return(0);
843 /* find least recently used */
844 n = 0;
845 if (honly != NULL)
846 n = hdlrulist(hb, n, FREEBEAMS, honly);
847 else
848 for (i = 0; hdlist[i] != NULL; i++)
849 n = hdlrulist(hb, n, FREEBEAMS, hdlist[i]);
850 /* free LRU beams */
851 for (i = 0; i < n; i++) {
852 hdfreebeam(hb[i].h, hb[i].b);
853 if ((freetarget -= hb[i].h->bi[hb[i].b].nrd) <= 0)
854 break;
855 }
856 hdsync(honly, 0); /* synchronize directories as necessary */
857 #ifdef DEBUG
858 sprintf(errmsg,
859 "%dK before, %dK after hdfreecache (%dK total), %d rays short\n",
860 membefore>>10, hdmemuse(0)>>10, hdmemuse(1)>>10, freetarget);
861 wputs(errmsg);
862 #endif
863 return(-freetarget); /* return how far past goal we went */
864 }
865
866
867 hddone(hp) /* clean up holodeck section and free */
868 register HOLO *hp; /* NULL means clean up all */
869 {
870 register int i;
871
872 if (hp == NULL) { /* NULL means clean up everything */
873 while (hdlist[0] != NULL)
874 hddone(hdlist[0]);
875 free((void *)hdfragl);
876 hdfragl = NULL; nhdfragls = 0;
877 return;
878 }
879 /* flush all data and free memory */
880 hdflush(hp);
881 /* release fragment resources */
882 hdrelease(hp->fd);
883 /* remove hp from active list */
884 for (i = 0; hdlist[i] != NULL; i++)
885 if (hdlist[i] == hp) {
886 while ((hdlist[i] = hdlist[i+1]) != NULL)
887 i++;
888 break;
889 }
890 free((void *)hp->bl); /* free beam list */
891 free((void *)hp); /* free holodeck struct */
892 }