#include #include #include #include "machdefs.h" #ifndef IBMVM #include #include #endif #include "filecache.h" #ifdef RFIO #include #endif #ifdef __mac__ #include #endif /* ++ Module Buffered I/O (C) Lib fsv include filecache.h Les fonctions décrites ci-dessous permettent de lire et d'écrire des fichiers avec une gestion de mémoire tampon, afin d'optimiser le débit d'entrée-sortie en cas d'utilisation lourde du positionnement dans le fichier (seek()). L'interface est similaire à celle des fonctions d'entrée sortie standard C ("fopen(...)", "fread(...)", ...). Au moment de l'ouverture du fichier (par zfopen()), une liste chainée de zones mémoire, (des pages) est créé. Ces pages sont destinées a contenir une image mémoire des zones accédées du fichier au moment des opérations de lecture et d'écriture, réduisant ainsi le nombre des accés effectifs au fichier disque. La taille et le nombre de page allouées sont contrôlés par l'utilisateur. -- */ static int zf_prtlev = 0; /* Nouvelle-Fonction */ void zfSetPrtLevel(int lev) { zf_prtlev = lev; } int pgread(FILECACHE *fcp, long fr, long n, char *buff); int pgwrite(FILECACHE *fcp, long fr, long n, char *buff); /* ++ FILECACHE *zfopen(char *flnm, char *mode, int npg, int pgsiz) Ouverture du fichier "flnm", en mode lecture seule ou lecture-écriture. "npg" pages de tailles "pgsiz" sont allouées pour la mémoire tampon. Les caractères "rw+" peuvent être spécifié pour "mode". Si "npg <= 0", les fonctions standard "fseek()", "fread()" et "fwrite()" sont utilisées. void zfclose( FILECACHE *fcp ) Fermeture du fichier. Il est impératif d'appeler zfclose() si le fichier a été ouvert en écriture. void zfSetPrtLevel(int lev) Modification du niveau d'impression pour le debug. si "lev > 2" des statistiques concernant l'utilisation de la mémoire tampon sont imprimées à la fermeture du fichier. -- */ /* Nouvelle-Fonction */ FILECACHE *zfopen(char *flnm, char *mode, int npg, int pgsiz) { FILE *fip; FILECACHE *fcp; int i,j; DSKPAGE *first, *cur, *prev; if ( (fip=fopen(flnm,mode)) == NULL ) { puts("zfopen_Erreur - Erreur fopen !"); return(NULL); } if ( (fcp=malloc(sizeof(FILECACHE))) == NULL ) { fclose(fip); puts("zfopen_Erreur - Erreur malloc(fcp) !"); return(NULL); } if ( npg < 0 ) { npg = DEF_NPAGE ; pgsiz = DEF_PGSIZE ; } fcp->fip = fip; #if defined(IBMVM) fcp->fidesc = -1; #elif defined(HPUX) fcp->fidesc = (int)fip->__fileH*256+(int)fip->__fileL; #elif defined(__MWERKS__) //fcp->fidesc = (int)fip->_Handle; // ANSI ancien fcp->fidesc = (int)fip->handle; // MSL #elif defined(Linux) fcp->fidesc = (int)fip->_fileno; #else fcp->fidesc = (int)fip->_file; #endif fcp->fpos = 0; fcp->nread = fcp->nwrite = 0; fcp->totrd = fcp->totwr =0; fseek(fip,0,SEEK_END); fcp->fsz = ftell(fip); fseek(fip,0,SEEK_SET); fcp->rwfg = 0; for(i=0; irwfg = 1; fcp->memode = 0; fcp->first = fcp->last = NULL; fcp->pages = NULL; fcp->npage = fcp->pgsize = 0; if (npg <= 0) return(fcp); /* Si pas d'option caching */ if (pgsiz < MIN_PGSIZE) pgsiz = MIN_PGSIZE; if (npg < MIN_NPAGE) npg = MIN_NPAGE; fcp->memode = 1; fcp->npage = npg; fcp->pgsize = pgsiz; if ( ( first = (DSKPAGE *)malloc(npg*sizeof(DSKPAGE)) ) == NULL ) { fclose(fip); free(fcp); puts("zfopen_Erreur: Pb malloc(DSKPAGE) !"); return(NULL); } prev = NULL; cur = first-1; for(i=0; iwrfg = 0; cur->pgno = -1; if ( (cur->page=malloc(pgsiz)) == NULL) { for(j=0; jpage); free(first); free(fcp); fclose(fip); return(NULL); } memset( cur->page, pgsiz, '\0'); cur->next = cur+1; cur->prev = prev; prev = cur; } cur->next = NULL; fcp->last = cur; fcp->first = first; fcp->pages = first; if (zf_prtlev > 5) { printf("zfopen_Debug: NPage= %d , PgSize= %d \n", npg, pgsiz); cur = fcp->first; for (i=0; ipage, (unsigned long)cur->next); cur = cur->next; } } return(fcp); } /* Nouvelle-Fonction */ void zfclose( FILECACHE *fcp ) { float effr,effw; DSKPAGE *cur; int_4 pgsiz; long int fp; if (fcp == NULL) return; pgsiz = fcp->pgsize; cur = fcp->first; while (cur != NULL) { if ( cur->wrfg && fcp->rwfg ) { fp = cur->pgno*fcp->pgsize; #ifdef IBMVM fseek(fcp->fip, fp, SEEK_SET); fwrite(cur->page, 1, pgsiz, fcp->fip); #else lseek(fcp->fidesc, (off_t)fp, SEEK_SET); write(fcp->fidesc, cur->page, pgsiz); #endif fcp->nwrite ++; } free(cur->page); cur = cur->next; } if (zf_prtlev > 2) { if (fcp->nread > 0) effr = (float)(fcp->totrd)/(float)(fcp->nread*pgsiz); else effr = 1.0; if (fcp->nwrite > 0) effw = (float)(fcp->totwr)/(float)(fcp->nwrite*pgsiz); else effw = 1.0; puts(" ================= Statistiques Memoire Cache ================="); printf(" NPage= %d PgSize= %d \n", fcp->npage, fcp->pgsize); printf(" PgRead= %d TotRd= %ld TotRd/PgRead= %g \n", fcp->nread, fcp->totrd, effr); printf(" PgWrite= %d TotWr= %ld TotWr/PgWrite= %g \n", fcp->nwrite, fcp->totwr, effw); puts(" =============================================================="); } /* fcp->first a tourne et ne pointe plus vers la 1ere structure des DSKPAGES* */ free(fcp->pages); fclose(fcp->fip); free(fcp); return; } /* ++ int zfseek( FILECACHE *fcp, long int offset, int fg) Positionnement dans le fichier. "fg" peut valoir "SEEK_SET", "SEEK_CUR", "SEEK_END", pour un positionnement avec décalage "offset" à partir du début de fichier, de la position courante, ou de la fin du fichier. size_t zfread( void *buff, size_t size, size_t nitems, FILECACHE *fcp) Lecture à partir de la position courante. size_t zfwrite( void *buff, size_t size, size_t nitems, FILECACHE *fcp) Ecriture à partir de la position courante. -- */ /* Nouvelle-Fonction */ int zfseek( FILECACHE *fcp, long int offset, int fg) { long int newpos; if (fcp == NULL) return(-2); if ( !fcp->memode ) return ( fseek(fcp->fip, offset, fg) ); newpos = offset; if (fg == SEEK_SET) newpos = offset; if (fg == SEEK_CUR) newpos = fcp->fpos + offset; if (fg == SEEK_END) newpos = fcp->fsz - offset; if ( newpos < 0 ) return(-1); if ( !fcp->rwfg && (newpos >= fcp->fsz) ) return(-1); fcp->fpos = newpos; return(0); } /* Nouvelle-Fonction */ size_t zfread( void *buff, size_t size, size_t nitems, FILECACHE *fcp) { long int m,n; long int fr,nr; if (fcp == NULL) return(0); if ( !fcp->memode ) return ( fread(buff, size, nitems, fcp->fip) ); #ifdef DEBUG_FCACHE printf(" Debug_zfread pos,size,nitem= %d %d %d\n",fcp->fpos,size,nitems); #endif m = 0; n = size*nitems; if ( fcp->fpos+n > fcp->fsz ) n = fcp->fsz-fcp->fpos; if ( n <= 0) return(0); fr = fcp->fpos; fcp->totrd += n; nr = n; while ((m < n) && (nr > 0)) { #ifdef DEBUG_FCACHE printf(" Debug_zfread_2 fr,n,m= %d %d %d\n",fr,n,m); #endif nr = pgread(fcp,fr,(n-m), ((char *)buff)+m); m += nr; fr += nr; } fcp->fpos += m; return(m); } /* Nouvelle-Fonction */ int pgread(FILECACHE *fcp, long fr, long n, char *buff) { long int pgnum, pg; long int off, nr; long int fp; DSKPAGE *cur; pgnum = fr / fcp->pgsize; /* On regarde si la page est en memoire */ pg = -1; cur = fcp->first; while (cur != NULL) { if (cur->pgno < 0) break; if (cur->pgno == pgnum) { pg = pgnum; break; } cur = cur->next; } /* On la lit si elle n'y est pas */ if ( pg < 0) { cur = fcp->last; /* On reecrit la derniere page si necessaire */ if ( cur->wrfg && fcp->rwfg ) { fp = cur->pgno*fcp->pgsize; #ifdef IBMVM fseek(fcp->fip, fp, SEEK_SET); fwrite(cur->page, 1, fcp->pgsize, fcp->fip); #else lseek(fcp->fidesc, (off_t)fp, SEEK_SET); write(fcp->fidesc, cur->page, fcp->pgsize); #endif fcp->nwrite ++; } fp = pgnum*fcp->pgsize; #ifdef IBMVM fseek(fcp->fip, fp, SEEK_SET); fread(cur->page, 1, fcp->pgsize, fcp->fip); #else lseek(fcp->fidesc, (off_t)fp, SEEK_SET); read(fcp->fidesc, cur->page, fcp->pgsize); #endif cur->pgno = pgnum; cur->wrfg = 0; fcp->nread ++; } /* On reordonne les pages */ if ( cur != fcp->first ) { if ( cur == fcp->last ) { fcp->last = cur->prev; (fcp->last)->next = NULL; } else { (cur->prev)->next = cur->next; (cur->next)->prev = cur->prev; } (fcp->first)->prev = cur; cur->next = fcp->first; cur->prev = NULL; fcp->first = cur; } /* Copie ds buffer utilisateur */ off = fr - pgnum*fcp->pgsize; if ( (nr=fcp->pgsize-off) > n ) nr = n; memcpy(buff, (cur->page)+off, nr); return(nr); } /* Nouvelle-Fonction */ size_t zfwrite( void *buff, size_t size, size_t nitems, FILECACHE *fcp) { long int m,n; long int fr,nw; if (fcp == NULL) return(-1); if ( !fcp->rwfg ) return(-2); if ( !fcp->memode ) return ( fwrite(buff, size, nitems, fcp->fip) ); m = 0; n = size*nitems; if ( n <= 0) return(0); fr = fcp->fpos; fcp->totwr += n; nw = n; while ((m < n) && (nw > 0)) { nw = pgwrite(fcp,fr,(n-m), ((char*)buff)+m); m += nw; fr += nw; } fcp->fpos += m; if (fcp->fpos >= fcp->fsz) fcp->fsz = fcp->fpos+1; return(m); } /* Nouvelle-Fonction */ int pgwrite(FILECACHE *fcp, long fr, long n, char *buff) { long int pgnum, pg; long int off, nw; long int fp; DSKPAGE *cur; pgnum = fr / fcp->pgsize; /* On regarde si la page est en memoire */ pg = -1; cur = fcp->first; while (cur != NULL) { if (cur->pgno < 0) break; if ( cur->pgno == pgnum) { pg = pgnum; break; } cur = cur->next; } /* On la lit si elle n'y est pas */ if ( pg < 0) { cur = fcp->last; /* On reecrit la derniere page si necessaire */ if ( cur->wrfg && fcp->rwfg) { fp = cur->pgno*fcp->pgsize; #ifdef IBMVM fseek(fcp->fip, fp, SEEK_SET); fwrite(cur->page, 1, fcp->pgsize, fcp->fip); #else lseek(fcp->fidesc, (off_t)fp, SEEK_SET); write(fcp->fidesc, cur->page, fcp->pgsize); #endif fcp->nwrite ++; } fp = pgnum*fcp->pgsize; if ( (fp + fcp->pgsize) >= fcp->fsz ) /* remise a zero de la page */ memset( cur->page, fcp->pgsize, '\0'); #ifdef IBMVM fseek(fcp->fip, fp, SEEK_SET); fread(cur->page, 1, fcp->pgsize, fcp->fip); #else lseek(fcp->fidesc, (off_t)fp, SEEK_SET); read(fcp->fidesc, cur->page, fcp->pgsize); #endif cur->pgno = pgnum; cur->wrfg = 0; fcp->nread ++; } /* On reordonne les pages */ if ( cur != fcp->first ) { if ( cur == fcp->last ) { fcp->last = cur->prev; (fcp->last)->next = NULL; } else { (cur->prev)->next = cur->next; (cur->next)->prev = cur->prev; } (fcp->first)->prev = cur; cur->next = fcp->first; cur->prev = NULL; fcp->first = cur; } /* Copie ds buffer utilisateur */ off = fr - pgnum*fcp->pgsize; if ( (nw=fcp->pgsize-off) > n ) nw = n; memcpy((cur->page)+off, buff, nw); cur->wrfg = 1; return(nw); }