ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/holofile.c
Revision: 3.53
Committed: Mon Oct 20 16:01:55 2003 UTC (20 years, 6 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 3.52: +17 -13 lines
Log Message:
Included "platform.h" wherever lseek() was called

File Contents

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