ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/holofile.c
Revision: 3.62
Committed: Tue Dec 19 20:22:36 2023 UTC (10 months, 1 week ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 3.61: +3 -3 lines
Log Message:
perf(rhcopy): Increased default memory cache size

File Contents

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