# include # include # include # include # include "globs.h" # include SCCSID(@(#)openrs.c 8.2 1/15/85) /* Defined constants for dtmode field above */ # define DTALLOC 0 /* descriptor allocated */ # define DTREL 1 /* has been openr'd -1 */ # define DTATTS 2 /* has rel+atts but not opened */ # define DTREAD 3 /* currently open for reading */ # define DTWRITE 4 /* currently open for writing */ /* Allocation of descriptors */ /* Globals which count #files open and maximum # of files which can be open */ /* ** OPENRS -- routines associated with maintaining the range table for decomp ** ** openrs(root) -- fill range table info about each relation. ** ** closers() -- close all variables in range table. ** ** openr1(varno) -- fill range table for a particular relation. ** ** closer1(varno) -- close a particular relation. ** ** readopen(varno) -- open a variable for reading. returns descriptor. ** ** writeopen(varno) -- open a variable for writing. returns descriptor. ** ** initdesc() -- initialize the descriptor cache. ** ** reldescrip(varno) -- returns descriptor for var (has rel/atts ** but might not be open). ** ** desc_get(relnum, flag) -- finds a desc_tab & alloctes it for relnum. ** ** desc_lru() -- returns least recently used desc_tab. ** ** desc_top(desc_tab) -- makes desc_tab most recently used. ** ** desc_last(desc_tab) -- makes desc_tab the least recently used. ** ** Trace Flags: ** 62 */ /* ** Initdesc -- initialize descriptors for range table */ initdesc(mode) int mode; { register struct desc_tab *dt; register int i; extern int Equel; for (dt = De.de_desc, i = 0; dt <= &De.de_desc[MAXRELN - 1]; dt++, i++) { dt->dtmode = DTALLOC; dt->relnum = -2; /* unused relnum value */ dt->dtpos = i; /* lru order */ } /* ** Determine number of available file descriptors. ** av_files gives number of files that are def. open ** for users. if we will need to open a batch file, ** get rid of that also. */ De.de_dfiles = av_files(); if (mode != mdRETR) De.de_dfiles--; De.de_dopnfiles = 0; } /* ** Openrs -- open source relations for query. Fill values ** in range table. */ openrs(root) QTREE *root; { register QTREE *r; register int map, i; DESC *openr1(); r = root; map = r->sym.value.sym_root.lvarm | r->sym.value.sym_root.rvarm; # ifdef xDTR1 if (tTf(62, 0)) printf("OPENRS-root:%x,map:%o\n", r, map); # endif for (i = 0; i < MAXRANGE; i++) if (map & (01 << i)) openr1(i); } /* ** Close all open relations. ** If any relations were created but never ** opened, destroy them. The only ** situation under which that can occur ** is when a rub-out occurs at an ** in opportune moment or when an error ** occurs in ovqp. */ closers() { register int i; register struct desc_tab *dt; bool dstr_flag; for (dt = De.de_desc; dt <= &De.de_desc[MAXRELN - 1]; dt++) desc_close(dt); /* destroy any temps */ initp(); /* init parameters vector for destroys */ dstr_flag = FALSE; while (i = rnum_last()) { dstr_flag |= dstr_mark(i); /* indicate that there are relations to be destroyed */ } if (dstr_flag) call_dbu(mdDESTROY, TRUE); else resetp(); } /* ** Openr1 -- open relation to get relation relation tuple ** ** This will not open the relation for reading -- only ** for getting the first part of the descriptor filled */ DESC * openr1(var) int var; { register struct desc_tab *dt; register struct rang_tab *rp; register DESC *d; int i; struct desc_tab *desc_get(); extern char *rnum_convert(); rp = &De.de_rangev[var]; # ifdef xDTR1 if (tTf(62, 2)) printf("openr1: var %d (%s)\t", var, rnum_convert(rp->relnum)); # endif dt = desc_get(rp->relnum, TRUE); if (dt->dtmode == DTALLOC) { if (i = openr(&dt->desc, OR_RELTID, rnum_convert(rp->relnum))) syserr("openr1 open %d %s", i, rnum_convert(rp->relnum)); dt->dtmode = DTREL; } # ifdef xDTR1 if (tTf(62, 2)) printf("tups=%ld\n", dt->desc.reldum.reltups); # endif d = &dt->desc; rp->rtspec = d->reldum.relspec; rp->rtstat = d->reldum.relstat; rp->rtwid = d->reldum.relwid; rp->rtcnt = d->reldum.reltups; return (d); } /* ** CLOSER1 */ closer1(var) int var; { register struct desc_tab *dt; register struct rang_tab *rp; register int i; struct desc_tab *desc_get(); struct desc_tab *desc_last(); i = var; rp = &De.de_rangev[i]; # ifdef xDTR1 if (tTf(62, 4)) printf("closer1:var %d (%s)\n", i, rnum_convert(rp->relnum)); # endif if (dt = desc_get(rp->relnum, FALSE)) { /* currently a descriptor for rel */ desc_close(dt); dt->relnum = -2; desc_last(dt); } } /* ** READOPEN */ DESC * readopen(var) int var; { register struct desc_tab *dt; struct desc_tab *desc_get(); /* get descv for the relation */ dt = desc_get(De.de_rangev[var].relnum, TRUE); if (!(dt->dtmode == DTREAD || dt->dtmode == DTWRITE)) { /* not open for reading or writing */ openup(dt, var, OR_READ); /* open for reading */ } return (&dt->desc); } /* ** WRITEOPEN */ DESC * writeopen(var) int var; { register struct desc_tab *dt; /* get descv for the relation */ dt = desc_get(De.de_rangev[var].relnum, TRUE); if (dt->dtmode != DTWRITE) { /* not open for writing */ openup(dt, var, OR_WRITE); /* open for reading */ } return (&dt->desc); } /* ** SPECOPEN -- open for writing not associated with any variable */ DESC * specopen(relnum) int relnum; { register struct desc_tab *dt; struct desc_tab *desc_get(); dt = desc_get(relnum, TRUE); if (dt->dtmode != DTWRITE) openup(dt, -1, OR_WRITE); return (&dt->desc); } /* ** SPECCLOSE */ specclose(relnum) int relnum; { register struct desc_tab *dt; struct desc_tab *desc_get(); struct desc_tab *desc_last(); if (dt = desc_get(relnum, FALSE)) { desc_close(dt); desc_last(dt); dt->relnum = -2; } } /* ** Openup -- make sure that the given descriptor is open ** suitably for reading or writing. */ openup(dt1, varno, mode) struct desc_tab *dt1; int varno; int mode; { register struct desc_tab *dt; register int md, openmd; int i; extern char *rnum_convert(); char rnam_tmp[MAXNAME+3]; /* quick check to handle typical case of rel being already open */ md = mode; dt = dt1; if ((md != OR_WRITE && dt->dtmode == DTREAD) || dt->dtmode == DTWRITE) return; /* relation not opened correctly */ switch (dt->dtmode) { case DTALLOC: /* ** Descriptor allocated but nothing else. If this ** is for a variable then use openr1 to get range table ** info. Else open directly. */ if (varno < 0) { /* open unassociated with a range table variable */ openmd = md ? OR_WRITE : OR_READ; bmove(rnum_convert(dt->relnum), dt->desc.reldum.relid, MAXNAME); break; } /* open for range table variable */ openr1(varno); /* now fall through to DTREL case */ case DTREL: /* relation relation tuple present but nothing else */ openmd = md ? OR_AWRITE : OR_AREAD; /* open AREAD for read, AWRITE for write */ break; case DTATTS: /* relation & attributes filled but relation closed */ openmd = md ? OR_REWRITE : OR_REREAD; break; case DTREAD: /* relation open for reading but we need to write */ desc_close(dt); openmd = OR_REWRITE; break; default: syserr("openup:bad md %d", dt->dtmode); } /* close a previous file if necessary */ if (De.de_dopnfiles == De.de_dfiles) desc_victum(); /* close oldest file */ /* now open relation */ bmove(dt->desc.reldum.relid, rnam_tmp, MAXNAME + 3); if (i = openr(&dt->desc, openmd, rnam_tmp)) syserr("openup:openr %d,%d,%.12s,%s", i, openmd, rnam_tmp, rnum_convert(dt->relnum)); De.de_dopnfiles++; /* update mode of descriptor */ dt->dtmode = md ? DTWRITE : DTREAD; } /* ** DESC_GET */ struct desc_tab * desc_get(relnum, flag) int relnum; bool flag; { register struct desc_tab *dt, *ret; struct desc_tab *desc_lru(); ret = NULL; /* search for one currently allocated */ for (dt = &De.de_desc[0]; dt <= &De.de_desc[MAXRELN-1]; dt++) { if (dt->relnum == relnum) { ret = dt; # ifdef xDTR1 if (tTf(62, 3)) printf("found desc for %d\n", relnum); # endif break; } } if (ret == NULL && flag) { /* get a victim and deallocate desc */ ret = desc_lru(); /* deallocate */ # ifdef xDTR1 if (tTf(62, 5)) printf("trading %d for %d\n", ret->relnum, relnum); # endif desc_close(ret); /* allocate */ ret->relnum = relnum; ret->dtmode = DTALLOC; } if (ret != NULL) desc_top(ret); return (ret); } /* ** For text space reasons only, the close relation routine varies ** between decomp and decomp70. In decomp, the relation is opened ** only for reading and never for writing thus inpcloser() can be ** called. For decomp70 closer() must be called. If there were no ** text space shortage, then closer() could always be called. ** The routine init_decomp() assigned the value to Des_closefunc. */ extern int (*Des_closefunc)(); /* either &inpcloser or &closer */ desc_close(dt1) struct desc_tab *dt1; { register struct desc_tab *dt; register int i; dt = dt1; if (dt->dtmode == DTREAD || dt->dtmode == DTWRITE) { if (i = (*Des_closefunc)(&dt->desc)) syserr("desc_close:closer %d,%.12s", i, dt->desc.reldum.relid); De.de_dopnfiles--; dt->dtmode = DTATTS; } } /* ** Desc_top -- make the desc_tab entry "dtx" the most recently used. */ desc_top(dt1) struct desc_tab *dt1; { register struct desc_tab *dt, *dx; register int oldpos; dt = dt1; if ((oldpos = dt->dtpos) != 0) { /* descriptor isn't currently top */ for (dx = De.de_desc; dx <= &De.de_desc[MAXRELN-1]; dx++) if (dx->dtpos < oldpos) dx->dtpos++; /* make descriptor first */ dt->dtpos = 0; } } /* ** Desc_last -- make the desc_tab entry "dt" the least recently used. */ struct desc_tab * desc_last(dt) register struct desc_tab *dt; { register int oldpos; register struct desc_tab *dx; oldpos = dt->dtpos; for (dx = De.de_desc; dx <= &De.de_desc[MAXRELN-1]; dx++) if (dx->dtpos > oldpos) dx->dtpos--; /* make descriptor last */ dt->dtpos = MAXRELN - 1; } /* ** Desc_lru -- return least recently used descriptor */ struct desc_tab * desc_lru() { register struct desc_tab *dx; for (dx = De.de_desc; dx <= &De.de_desc[MAXRELN-1]; dx++) { if (dx->dtpos == MAXRELN - 1) return (dx); } syserr("desc_lru:no lru"); /*NOTREACHED*/ } desc_victum() { register struct desc_tab *dt, *old; old = NULL; for (dt = &De.de_desc[0]; dt <= &De.de_desc[MAXRELN-1]; dt++) { if (dt->dtmode == DTWRITE || dt->dtmode == DTREAD) { if (old == NULL || dt->dtpos > old->dtpos) old = dt; } } if (old == NULL) syserr("desc_victum:no victum %d,%d", De.de_dopnfiles, De.de_dfiles); desc_close(old); }