ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/holofile.c
Revision: 3.59
Committed: Fri Sep 3 23:52:42 2010 UTC (13 years, 8 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad4R2P2, rad5R0, rad4R2, rad4R1, rad4R2P1
Changes since 3.58: +3 -2 lines
Log Message:
Fixed portability issue for 64-bit systems

File Contents

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