aboutsummaryrefslogtreecommitdiff
path: root/sys/fmio/fmfcache.x
diff options
context:
space:
mode:
Diffstat (limited to 'sys/fmio/fmfcache.x')
-rw-r--r--sys/fmio/fmfcache.x395
1 files changed, 395 insertions, 0 deletions
diff --git a/sys/fmio/fmfcache.x b/sys/fmio/fmfcache.x
new file mode 100644
index 00000000..6e1d16fe
--- /dev/null
+++ b/sys/fmio/fmfcache.x
@@ -0,0 +1,395 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <syserr.h>
+include <error.h>
+include <fset.h>
+include "fmset.h"
+include "fmio.h"
+
+.help fcache
+.nf -------------------------------------------------------------------------
+FCACHE -- FMIO File (Buffer) Cache package.
+
+ This package is used to manage a cache of lfile data buffers maintained on
+a FMIO datafile. The number and size of data buffers is user configurable:
+the number of buffers by a call to FM_SETI to set FM_FCACHESIZE, and the buffer
+size by a call to FSETI to set the file buffer size.
+
+ fm_fcinit (fm, cachesize)
+ fm_fcdebug (fm, out, what)
+ fm_fcsync (fm)
+ fm_fcfree (fm)
+
+ fd = fm_getfd (fm, lfile, mode, type)
+ fm_retfd (fm, lfile)
+ fm_lockout (fm, lfile)
+ fm_unlock (fm, lfile)
+ bool = fm_locked (fm, lfile)
+
+The cache is a conventional LRU cache. FM_GETFD returns the file descriptor
+of an open, cached file opened on an lfile, locking the file in the cache in
+the process. A subsequent call to FM_RETFD is required to allow the cache
+slot to be reused. FM_LOCKOUT may be used to lock a particular lfile out of
+the cache; FM_UNLOCK releases the lock.
+.endhelp --------------------------------------------------------------------
+
+define LEN_FCACHE (3+($1)*LEN_FSLOT) # len = LEN_FCACHE(cachesize)
+define FC_NFILES Memi[$1] # number of files in cache
+define FC_REFCNT Memi[$1+1] # cache reference count
+define FC_LFSTAT Memi[$1+2] # lfile statistics array
+define FC_FS ((($2)-1)*LEN_FSLOT+($1)+3) # get slot pointer
+
+define LEN_FSLOT 4
+define FC_NREF Memi[$1] # number of refs to this slot
+define FC_LRU Memi[$1+1] # LRU count for slot
+define FC_LFILE Memi[$1+2] # lfile assigned to slot
+define FC_FD Memi[$1+3] # file descriptor
+
+
+# FM_GETFD -- Map a FIO file descriptor onto an lfile and return the file
+# descriptor. The opened file descriptor remains in the cache after the
+# access, until the file ages out of the cache.
+
+int procedure fm_getfd (fm, lfile, mode, type)
+
+pointer fm # FMIO descriptor
+int lfile # lfile to be opened
+int mode # file access mode
+int type # file type
+
+int acmode, lru, i
+pointer oldest, fc, fs, st
+
+bool fm_locked()
+pointer fm_findlf()
+int fm_fopen(), fstati()
+errchk fm_fopen, fm_fcinit, syserrs, close
+define ref_ 91
+
+begin
+ fc = FM_FCACHE(fm)
+ if (fc == NULL) {
+ call fm_fcinit (fm, FM_SZFCACHE(fm))
+ fc = FM_FCACHE(fm)
+ }
+
+ # Keep debug statistics on lfile accesses.
+ st = FC_LFSTAT(fc)
+ if (st != NULL)
+ Mems[st+lfile] = Mems[st+lfile] + 1
+
+ fs = fm_findlf (fc, lfile)
+ if (fs != NULL) {
+ # If lfile is already in the cache and the new mode is NEW_FILE,
+ # or we need write perm and do not currently have it, close and
+ # reopen the lfile with the desired mode.
+
+ if (mode == NEW_FILE ||
+ (mode != READ_ONLY && fstati (FC_FD(fs), F_WRITE) == NO)) {
+ref_
+ if (FC_NREF(fs) > 1)
+ call syserrs (SYS_FMFSINUSE, FM_DFNAME(fm))
+ if (FC_NREF(fs) == 1)
+ call close (FC_FD(fs))
+ if (fm_locked (fm, lfile))
+ call syserrs (SYS_FMLFLOCKED, FM_DFNAME(fm))
+
+ if (mode == WRITE_ONLY || mode == APPEND)
+ acmode = READ_WRITE
+ else
+ acmode = mode
+
+ FC_FD(fs) = fm_fopen (fm, lfile, acmode, type)
+ FC_NREF(fs) = 1
+ FC_LFILE(fs) = lfile
+ }
+
+ # Reference the cached lfile.
+ FC_REFCNT(fc) = FC_REFCNT(fc) + 1
+ FC_LRU(fs) = FC_REFCNT(fc)
+ FC_NREF(fs) = FC_NREF(fs) + 1
+ if (mode == APPEND)
+ call seek (FC_FD(fs), EOFL)
+
+ return (FC_FD(fs))
+
+ } else {
+ # Lfile is not in cache. Find the oldest slot.
+ oldest = NULL
+ lru = NULL
+ do i = 1, FC_NFILES(fc) {
+ fs = FC_FS(fc,i)
+ if (FC_NREF(fs) <= 1)
+ if (lru == NULL || FC_LRU(fs) < lru) {
+ lru = FC_LRU(fs)
+ oldest = fs
+ if (FC_NREF(fs) <= 0)
+ break
+ }
+ }
+
+ # Abort if all cache slots are busy.
+ if (oldest == NULL)
+ call syserrs (SYS_FMFCFULL, FM_DFNAME(fm))
+
+ # Replace the file in the cache, and return new descriptor.
+ fs = oldest
+ goto ref_
+ }
+end
+
+
+# FM_RETFD -- Return a cached file, i.e., decrement the reference count for
+# the file so that it may be returned. If FM_RETFD is called when the file
+# is sitting in the cache idle, the file is physically closed (i.e., a GETFD
+# followed by one RETFD leaves the file cached and idle, ready for another
+# GETFD without losing context, but another RETFD while the file is idle
+# closes the file and removes it from the cache).
+
+procedure fm_retfd (fm, lfile)
+
+pointer fm #I FMIO descriptor
+int lfile #I lfile to be returned
+
+pointer fc, fs
+pointer fm_findlf()
+errchk fm_fcinit
+
+begin
+ fc = FM_FCACHE(fm)
+ if (fc == NULL) {
+ call fm_fcinit (fm, FM_SZFCACHE(fm))
+ fc = FM_FCACHE(fm)
+ }
+
+ fs = fm_findlf (fc, lfile)
+ if (fs != NULL) {
+ FC_NREF(fs) = FC_NREF(fs) - 1
+ if (FC_NREF(fs) <= 0) {
+ call close (FC_FD(fs))
+ FC_NREF(fs) = 0
+ }
+ }
+end
+
+
+# FM_LOCKOUT -- Lock an lfile out of the file cache.
+
+procedure fm_lockout (fm, lfile)
+
+pointer fm #I FMIO descriptor
+int lfile #I lfile to be locked out
+
+pointer fc, fs, lf
+pointer fm_findlf()
+errchk fm_fcinit, close, syserrs
+
+begin
+ fc = FM_FCACHE(fm)
+ if (fc == NULL) {
+ call fm_fcinit (fm, FM_SZFCACHE(fm))
+ fc = FM_FCACHE(fm)
+ }
+
+ # Close lfile if it is already in the cache, but idle.
+ fs = fm_findlf (fc, lfile)
+ if (fs != NULL) {
+ if (FC_NREF(fs) > 1)
+ call syserrs (SYS_FMLOKACTLF, FM_DFNAME(fm))
+ FC_NREF(fs) = FC_NREF(fs) - 1
+ if (FC_NREF(fs) <= 0) {
+ call close (FC_FD(fs))
+ FC_NREF(fs) = 0
+ }
+ }
+
+ # Set the lockout bit in the file table.
+ lf = FM_FTABLE(fm) + lfile * LEN_FTE
+ LF_FLAGS(lf) = or (LF_FLAGS(lf), LFF_LOCKOUT)
+end
+
+
+# FM_UNLOCK -- Unlock an lfile.
+
+procedure fm_unlock (fm, lfile)
+
+pointer fm #I FMIO descriptor
+int lfile #I lfile to be locked out
+
+pointer lf
+
+begin
+ # Clear the lockout bit in the file table.
+ lf = FM_FTABLE(fm) + lfile * LEN_FTE
+ LF_FLAGS(lf) = and (LF_FLAGS(lf), not(LFF_LOCKOUT))
+end
+
+
+# FM_LOCKED -- Test the lfile lockout bit.
+
+bool procedure fm_locked (fm, lfile)
+
+pointer fm #I FMIO descriptor
+int lfile #I lfile to be locked out
+
+pointer lf
+
+begin
+ # Test the lockout bit in the file table.
+ lf = FM_FTABLE(fm) + lfile * LEN_FTE
+ return (and (LF_FLAGS(lf), LFF_LOCKOUT) != 0)
+end
+
+
+# FM_FINDLF -- Search the cache for the given lfile.
+
+pointer procedure fm_findlf (fc, lfile)
+
+pointer fc #I file cache descriptor
+int lfile #I lfile to search for
+
+int i
+pointer fs
+
+begin
+ do i = 1, FC_NFILES(fc) {
+ fs = FC_FS(fc,i)
+ if (FC_NREF(fs) != 0 && FC_LFILE(fs) == lfile)
+ return (fs)
+ }
+
+ return (NULL)
+end
+
+
+# FM_FCDEBUG -- Print debug info describing the contents and status of the
+# file cache.
+
+procedure fm_fcdebug (fm, out, what)
+
+pointer fm #I FMIO descriptor
+int out #I output file
+int what #I type of debug output
+
+int nref, i
+pointer fc, fs, st
+errchk fm_fcinit
+
+begin
+ fc = FM_FCACHE(fm)
+ if (fc == NULL) {
+ call fm_fcinit (fm, FM_SZFCACHE(fm))
+ fc = FM_FCACHE(fm)
+ }
+
+ # Print cache status.
+ if (and (what, FCD_CACHE) != 0) {
+ call fprintf (out, "# LRU NREF LFILE FD\n")
+ do i = 1, FC_NFILES(fc) {
+ fs = FC_FS(fc,i)
+ call fprintf (out, "%6d %4d %5d %3d\n")
+ call pargi (FC_LRU(fs))
+ call pargi (FC_NREF(fs))
+ if (FC_NREF(fs) > 0) {
+ call pargi (FC_LFILE(fs))
+ call pargi (FC_FD(fs))
+ } else {
+ call pargi (0)
+ call pargi (0)
+ }
+ }
+ }
+
+ # Print lfile access statistics.
+ if (and (what, FCD_LFSTATISTICS) != 0) {
+ st = FC_LFSTAT(fc)
+ if (st != NULL) {
+ call fprintf (out, "-------- getfd's per lfile ---------\n")
+ do i = 0, FM_NLFILES(fm) {
+ nref = Mems[st+i]
+ if (nref > 0) {
+ call fprintf (out, "%4d %4d\n")
+ call pargi (i)
+ call pargi (nref)
+ }
+ }
+ }
+ }
+end
+
+
+# FM_FCINIT -- Init the file cache.
+
+procedure fm_fcinit (fm, cachesize)
+
+pointer fm #I FMIO descriptor
+int cachesize #I size of cache, file slots
+
+pointer fc
+
+begin
+ if (FM_FCACHE(fm) != NULL)
+ call fm_fcfree (fm)
+
+ call calloc (fc, LEN_FCACHE(cachesize), TY_STRUCT)
+ call calloc (FC_LFSTAT(fc), FM_NLFILES(fm)+1, TY_SHORT)
+ FC_NFILES(fc) = cachesize
+ FC_REFCNT(fc) = 1
+
+ FM_FCACHE(fm) = fc
+end
+
+
+# FM_FCFREE -- Shutdown the file cache and free all resources, ignoring
+# all file reference counts.
+
+procedure fm_fcfree (fm)
+
+pointer fm #I FMIO descriptor
+
+int i
+pointer fc, fs
+
+begin
+ fc = FM_FCACHE(fm)
+ if (fc == NULL)
+ return
+
+ # Update the datafile.
+ call fm_fcsync (fm)
+
+ # Close any cached files.
+ do i = 1, FC_NFILES(fc) {
+ fs = FC_FS(fc,i)
+ if (FC_NREF(fs) >= 1)
+ iferr (call close (FC_FD(fs)))
+ call erract (EA_WARN)
+ }
+
+ call mfree (FC_LFSTAT(fc), TY_SHORT)
+ call mfree (FM_FCACHE(fm), TY_STRUCT)
+end
+
+
+# FM_FCSYNC -- Sync the file cache and datafile.
+
+procedure fm_fcsync (fm)
+
+pointer fm #I FMIO descriptor
+
+int i
+pointer fc, fs
+
+begin
+ fc = FM_FCACHE(fm)
+ if (fc != NULL) {
+ do i = 1, FC_NFILES(fc) {
+ fs = FC_FS(fc,i)
+ if (FC_NREF(fs) >= 1)
+ iferr (call flush (FC_FD(fs)))
+ call erract (EA_WARN)
+ }
+ }
+
+ call fm_sync (fm)
+end