/* * Copyright 1987 Alan Kent * * Permission is granted to redistribute this code as long * as this message is retained in the code and the code is * not sold without written permission from the author. * * UUCP: {seismo,hplabs,mcvax,ukc,nttlab}!munnari!goanna.oz!ajk * ACSnet: ajk@goanna.oz * ARPA: munnari!goanna.oz!ajk@SEISMO.ARPA */ #include "hd.h" extern struct Node *RemTail (); #define CACHE_SIZE 10 static struct cache { struct Node node; struct posn posn; UBYTE * buf; } cache[ CACHE_SIZE ]; static struct List history; void clear_all () { register int i; register struct cache *c; NewList ( &history ); for ( i = 0; i < CACHE_SIZE; i++ ) { c = &cache[i]; c->posn.cylinder = -1; c->node.ln_Pri = 0; AddTail ( &history , c ); } } void flush_all () { } int init_cache () { int i; for ( i = 0; i < CACHE_SIZE; i++ ) { if ( ( cache[i].buf = (UBYTE *) AllocMem ( (LONG)HD_SECTOR * first.sectors , (LONG)MEMF_CLEAR ) ) == NULL ) { while ( --i >= 0 ) FreeMem ( cache[i].buf , (LONG)HD_SECTOR * first.sectors ); return ( -1 ); } } clear_all (); return ( 0 ); } void free_cache () { register int i; for ( i = 0; i < CACHE_SIZE; i++ ) FreeMem ( cache[i].buf , (LONG)HD_SECTOR * first.sectors ); } UBYTE * read_cache ( posn ) struct posn *posn; { register struct cache *c; int status; static UBYTE single_buf[ HD_SECTOR ]; /* see if track is in the cache */ for ( c = (struct cache *) history.lh_Head; c->node.ln_Succ != NULL; c = (struct cache *) c->node.ln_Succ ) { if ( posn->cylinder == c->posn.cylinder && posn->surface == c->posn.surface ) { /* recalculate priority so is not pushed out of list */ Remove ( c ); calc_priority ( c ); Enqueue ( &history , c ); return ( &c->buf[ posn->sector * (LONG)HD_SECTOR ] ); } } /* ok, decrease cache weights so new tracks have better chance */ for ( c = (struct cache *) history.lh_Head; c->node.ln_Succ != NULL; c = (struct cache *) c->node.ln_Succ ) { if ( c->node.ln_Pri > 0 ) c->node.ln_Pri--; } /* not in cache */ c = (struct cache *) RemTail ( &history ); c->posn = *posn; status = read_track ( &c->posn , c->buf ); if ( status != 0 ) { AddTail ( &history , c ); c->posn.cylinder = -1; status = read_sector ( &c->posn , &single_buf[0] ); if ( status != 0 ) status = read_sector ( &c->posn , &single_buf[0] ); if ( status != 0 ) status = read_sector ( &c->posn , &single_buf[0] ); if ( status != 0 ) return ( NULL ); return ( &single_buf[0] ); } calc_priority ( c ); Enqueue ( &history , c ); return ( &c->buf[ posn->sector * (LONG)HD_SECTOR ] ); } void write_cache ( posn , buf ) register struct posn *posn; UBYTE *buf; { register struct cache *c; /* if in cache, make sure updated in cache */ for ( c = (struct cache *) history.lh_Head; c->node.ln_Succ != NULL; c = (struct cache *) c->node.ln_Succ ) { if ( posn->cylinder == c->posn.cylinder && posn->surface == c->posn.surface ) { /* update cache */ copy_sector ( buf , &c->buf[ posn->sector * (LONG)HD_SECTOR ] ); break; } } write_sector ( posn , buf ); } static calc_priority ( c ) struct cache *c; { register UBYTE *p; register LONG type , subtype; register int sector; register int priority; /* ok, now lets peek inside the sectors to see if this track */ /* contains anything juicy. Directory entries get extra points */ /* because of the way they are scattered all over the place. */ /* Data blocks get less because they are only likely to be used */ /* once. */ priority = 0; for ( sector = 0, p = c->buf; sector < first.sectors; sector++, p += HD_SECTOR ) { type = ((LONG*)p) [ 0 ]; subtype = ((LONG*)p) [ 127 ]; if ( type == 2 && subtype == 2 /* File Header */ || type == 2 && subtype == -3 /* User Directory */ || type == 16 && subtype == -3 ) /* file extension */ priority += 2; if ( type == 8 ) /* data block */ priority += 1; } c->node.ln_Pri = priority; }