From bf8a5b89ca4d04941e1f0f22a585eb696d290c10 Mon Sep 17 00:00:00 2001 From: "dveditz%netscape.com" Date: Fri, 17 Sep 1999 01:32:00 +0000 Subject: [PATCH] Buffered I/O for registry performance git-svn-id: svn://10.0.0.236/trunk@47893 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/modules/libreg/src/Makefile.in | 11 +- mozilla/modules/libreg/src/makefile.win | 23 +- mozilla/modules/libreg/src/mmapio.c | 69 +-- mozilla/modules/libreg/src/mmapio.h | 2 +- mozilla/modules/libreg/src/nr_bufio.c | 562 ++++++++++++++++++++++++ mozilla/modules/libreg/src/nr_bufio.h | 46 ++ mozilla/modules/libreg/src/reg.c | 154 +------ mozilla/modules/libreg/src/vr_stubs.h | 129 ++++-- 8 files changed, 773 insertions(+), 223 deletions(-) create mode 100644 mozilla/modules/libreg/src/nr_bufio.c create mode 100644 mozilla/modules/libreg/src/nr_bufio.h diff --git a/mozilla/modules/libreg/src/Makefile.in b/mozilla/modules/libreg/src/Makefile.in index baf78dd9fb5..98efa619ff4 100644 --- a/mozilla/modules/libreg/src/Makefile.in +++ b/mozilla/modules/libreg/src/Makefile.in @@ -29,7 +29,7 @@ REQUIRES = libreg pref js PROGRAM = vreg -CSRCS = reg.c VerReg.c vr_stubs.c +CSRCS = reg.c VerReg.c vr_stubs.c nr_bufio.c BIN_SRCS = VerReg.c reg.c vr_stubs.c PROGOBJS = $(addprefix R_,$(BIN_SRCS:.c=.o)) @@ -40,11 +40,12 @@ override NO_STATIC_LIB= include $(topsrcdir)/config/config.mk +DEFINES += -DUSE_BUFFERED_REGISTRY_IO # Memory mapped files are not supported under QNX, Neutrino, HP-UX and BeOS -ifeq (,$(filter BeOS HP-UX QNX,$(OS_ARCH))) -CSRCS += mmapio.c -DEFINES += -DUSE_MMAP_REGISTRY_IO -endif +#ifeq (,$(filter BeOS HP-UX QNX,$(OS_ARCH))) +#CSRCS += mmapio.c +#DEFINES += -DUSE_MMAP_REGISTRY_IO +#endif include $(topsrcdir)/config/rules.mk diff --git a/mozilla/modules/libreg/src/makefile.win b/mozilla/modules/libreg/src/makefile.win index 8a62439189e..7e3c0dce0b1 100644 --- a/mozilla/modules/libreg/src/makefile.win +++ b/mozilla/modules/libreg/src/makefile.win @@ -31,11 +31,10 @@ DEPTH= ..\..\.. MAKE_OBJ_TYPE=DLL -#//------------------------------------------------------------------------ -#// -#// Define any Public Make Variables here: (ie. PDFFILE, MAPFILE, ...) -#// -#//------------------------------------------------------------------------ +#//--- pick at most one of the IO types. Commenting both of +#//--- them out gives you normal NSPR I/O +USE_BUFFERED_REGISTRY_IO=1 +#USE_MMAP_REGISTRY_IO=1 #//------------------------------------------------------------------------ #// @@ -47,7 +46,12 @@ OBJS= \ .\$(OBJDIR)\reg.obj \ .\$(OBJDIR)\VerReg.obj \ .\$(OBJDIR)\vr_stubs.obj \ -# .\$(OBJDIR)\mmapio.obj \ +!if defined(USE_MMAP_REGISTRY_IO) + .\$(OBJDIR)\mmapio.obj \ +!endif +!if defined(USE_BUFFERED_REGISTRY_IO) + .\$(OBJDIR)\nr_bufio.obj \ +!endif $(NULL) #//------------------------------------------------------------------------ @@ -69,7 +73,12 @@ DLL=$(OBJDIR)\$(DLLNAME).dll #// #//------------------------------------------------------------------------ -#LCFLAGS= -DUSE_MMAP_REGISTRY_IO +!if defined(USE_MMAP_REGISTRY_IO) +LCFLAGS=$(LCFLAGS) -DUSE_MMAP_REGISTRY_IO +!endif +!if defined(USE_BUFFERED_REGISTRY_IO) +LCFLAGS=$(LCFLAGS) -DUSE_BUFFERED_REGISTRY_IO +!endif LLIBS = \ $(LIBNSPR) \ diff --git a/mozilla/modules/libreg/src/mmapio.c b/mozilla/modules/libreg/src/mmapio.c index d5c2ff3f2db..4d21a9a7b5d 100644 --- a/mozilla/modules/libreg/src/mmapio.c +++ b/mozilla/modules/libreg/src/mmapio.c @@ -17,6 +17,7 @@ * * Contributor(s): James L. Nance */ +#include #include "mmapio.h" #include "prmem.h" #include "prlog.h" @@ -38,16 +39,16 @@ PRStatus mmio_FileSeek(MmioFile *mmio, PRInt32 offset, PRSeekWhence whence) switch(whence) { case PR_SEEK_SET: - mmio->pos = offset; - break; - case PR_SEEK_END: - mmio->pos = mmio->fsize + offset; - break; - case PR_SEEK_CUR: - mmio->pos = mmio->pos + offset; - break; - default: - return PR_FAILURE; + mmio->pos = offset; + break; + case PR_SEEK_END: + mmio->pos = mmio->fsize + offset; + break; + case PR_SEEK_CUR: + mmio->pos = mmio->pos + offset; + break; + default: + return PR_FAILURE; } if(mmio->pos<0) { @@ -75,28 +76,28 @@ PRInt32 mmio_FileRead(MmioFile *mmio, char *dest, PRInt32 count) /* Check to see if we need to remap for this read */ if(mmio->pos+count > mmio->msize) { - if(mmio->addr && mmio->msize) { - PR_ASSERT(mmio->fileMap); - PR_MemUnmap(mmio->addr, mmio->msize); - PR_CloseFileMap(mmio->fileMap); - mmio->addr = NULL; - mmio->msize = 0; - } + if(mmio->addr && mmio->msize) { + PR_ASSERT(mmio->fileMap); + PR_MemUnmap(mmio->addr, mmio->msize); + PR_CloseFileMap(mmio->fileMap); + mmio->addr = NULL; + mmio->msize = 0; + } - LL_UI2L(fsize_l, mmio->fsize); - mmio->fileMap = PR_CreateFileMap(mmio->fd, fsize_l, prot); + LL_UI2L(fsize_l, mmio->fsize); + mmio->fileMap = PR_CreateFileMap(mmio->fd, fsize_l, prot); - if(!mmio->fileMap) { - return -1; - } + if(!mmio->fileMap) { + return -1; + } - mmio->addr = PR_MemMap(mmio->fileMap, 0, fsize_l); + mmio->addr = PR_MemMap(mmio->fileMap, 0, fsize_l); - if(!mmio->addr) { - return -1; - } + if(!mmio->addr) { + return -1; + } - mmio->msize = mmio->fsize; + mmio->msize = mmio->fsize; } memcpy(dest, mmio->addr+mmio->pos, count); @@ -113,16 +114,16 @@ PRInt32 mmio_FileWrite(MmioFile *mmio, const char *src, PRInt32 count) if(mmio->needSeek) { PR_Seek(mmio->fd, mmio->pos, PR_SEEK_SET); - mmio->needSeek = PR_FALSE; + mmio->needSeek = PR_FALSE; } wcode = PR_Write(mmio->fd, src, count); if(wcode>0) { mmio->pos += wcode; - if(mmio->pos>mmio->fsize) { - mmio->fsize=mmio->pos; - } + if(mmio->pos>mmio->fsize) { + mmio->fsize=mmio->pos; + } } return wcode; @@ -136,9 +137,9 @@ PRInt32 mmio_FileTell(MmioFile *mmio) PRStatus mmio_FileClose(MmioFile *mmio) { if(mmio->addr && mmio->msize) { - PR_ASSERT(mmio->fileMap); + PR_ASSERT(mmio->fileMap); PR_MemUnmap(mmio->addr, mmio->msize); - PR_CloseFileMap(mmio->fileMap); + PR_CloseFileMap(mmio->fileMap); } PR_Close(mmio->fd); @@ -163,7 +164,7 @@ MmioFile *mmio_FileOpen(char *path, PRIntn flags, PRIntn mode) mmio = PR_MALLOC(sizeof(MmioFile)); if(!mmio || PR_FAILURE==PR_GetOpenFileInfo(fd, &info)) { - PR_Close(fd); + PR_Close(fd); return NULL; } diff --git a/mozilla/modules/libreg/src/mmapio.h b/mozilla/modules/libreg/src/mmapio.h index 387a1916e5b..90593acaf4c 100644 --- a/mozilla/modules/libreg/src/mmapio.h +++ b/mozilla/modules/libreg/src/mmapio.h @@ -18,7 +18,7 @@ * Contributor(s): James L. Nance */ -#include +#include "prio.h" typedef struct MmioFileStruct MmioFile; diff --git a/mozilla/modules/libreg/src/nr_bufio.c b/mozilla/modules/libreg/src/nr_bufio.c new file mode 100644 index 00000000000..61a096878eb --- /dev/null +++ b/mozilla/modules/libreg/src/nr_bufio.c @@ -0,0 +1,562 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator + * + * The Initial Developer of the Original Code is Netscape Communications + * Corporation. Portions created by Netscape are + * Copyright (C) 1999 Netscape Communications Corporation. All Rights + * Reserved. + * + * Contributors: + * Daniel Veditz + */ + +/*------------------------------------------------------------------------ + * nr_bufio + * + * Buffered I/O routines to improve registry performance + * the routines mirror fopen(), fclose() et al + * + * Inspired by the performance gains James L. Nance + * got using NSPR memory-mapped I/O for the registry. Unfortunately NSPR + * doesn't support mmapio on the Mac. + *-----------------------------------------------------------------------*/ + +#include +#include +#include +#if defined(XP_MAC) + #include +#endif + +#include "prerror.h" +#include "prlog.h" + +#include "vr_stubs.h" +#include "nr_bufio.h" + + + +#define STARTS_IN_BUF(f) ((f->fpos >= f->datastart) && \ + (f->fpos < (f->datastart+f->datasize))) + +#define ENDS_IN_BUF(f,c) (((f->fpos + c) > (PRUint32)f->datastart) && \ + ((f->fpos + c) <= (PRUint32)(f->datastart+f->datasize))) + + + + + +#define BUFIO_BUFSIZE 0x10000 + +struct BufioBufStruct +{ + PRInt32 datastart; /* The file position for the buffer start */ + PRInt32 datasize; /* the amount of data in the buffer */ + PRBool dirty; /* if the buffer has been written to */ + PRInt32 dirtystart; /* lowest offset written to */ + PRInt32 dirtyend; /* end of the written area */ +} BufioBuf; + +struct BufioFileStruct +{ + FILE *fd; /* real file descriptor */ + PRInt32 fsize; /* total size of file */ + PRInt32 fpos; /* our logical position in the file */ + PRInt32 datastart; /* the file position at which the buffer starts */ + PRInt32 datasize; /* the amount of data actually in the buffer*/ + PRBool bufdirty; /* whether the buffer been written to */ + PRInt32 dirtystart; + PRInt32 dirtyend; + PRBool readOnly; /* whether the file allows writing or not */ + char *data; /* the data buffer */ +}; + + +static PRBool _bufio_loadBuf( BufioFile* file, PRUint32 count ); +static int _bufio_flushBuf( BufioFile* file ); + + + +/** + * like fopen() this routine takes *native* filenames, not NSPR names. + */ +BufioFile* bufio_Open(const char* name, const char* mode) +{ + FILE *fd; + BufioFile *file = NULL; + PRBool cleanup = PR_FALSE; + + fd = fopen( name, mode ); + + if ( fd ) + { + /* file opened successfully, initialize the bufio structure */ + + file = PR_NEWZAP( BufioFile ); + if ( file ) + { + file->fd = fd; + + file->data = (char*)PR_Malloc( BUFIO_BUFSIZE ); + if ( file->data ) + { + /* get file size to finish initialization of bufio */ + if ( !fseek( fd, 0, SEEK_END ) ) + { + file->fsize = ftell( fd ); + + file->readOnly = strcmp(mode,XP_FILE_READ) == 0 || + strcmp(mode,XP_FILE_READ_BIN) == 0; + } + else + { + PR_Free( file->data ); + PR_DELETE( file ); + } + } + else + PR_DELETE( file ); + } + + /* close file if we couldn't create BufioFile */ + if (!file) + { + fclose( fd ); + PR_SetError( PR_OUT_OF_MEMORY_ERROR, 0 ); + } + } + else + { + /* couldn't open file. Figure out why and set NSPR errors */ + + switch (errno) + { + /* file not found */ +#ifdef XP_MAC + case fnfErr: +#else + case ENOENT: +#endif + PR_SetError(PR_FILE_NOT_FOUND_ERROR,0); + break; + + /* file in use */ +#ifdef XP_MAC + case opWrErr: +#else + case EACCES: +#endif + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR,0); + break; + + default: + PR_SetError(PR_UNKNOWN_ERROR,0); + break; + } + } + + return file; +} + + + +/** + * close the buffered file and destroy BufioFile struct + */ +int bufio_Close(BufioFile* file) +{ + int retval = -1; + + if ( file ) + { + if ( file->bufdirty ) + _bufio_flushBuf( file ); + + retval = fclose( file->fd ); + + if ( file->data ) + PR_Free( file->data ); + + PR_DELETE( file ); + } + + return retval; +} + + + +/** + * change the logical position in the file. Equivalent to fseek() + */ +int bufio_Seek(BufioFile* file, PRInt32 offset, int whence) +{ + if (!file) + return -1; + + switch(whence) + { + case SEEK_SET: + file->fpos = offset; + break; + case SEEK_END: + file->fpos = file->fsize + offset; + break; + case SEEK_CUR: + file->fpos = file->fpos + offset; + break; + default: + return -1; + } + + if ( file->fpos < 0 ) + file->fpos = 0; + + return 0; +} + + + +/** + * like ftell() returns the current position in the file, or -1 for error + */ +PRInt32 bufio_Tell(BufioFile* file) +{ + if (file) + return file->fpos; + else + return -1; +} + + + +PRUint32 bufio_Read(BufioFile* file, char* dest, PRUint32 count) +{ + PRInt32 startOffset; + PRInt32 endOffset; + PRInt32 leftover; + PRUint32 bytesCopied; + PRUint32 bytesRead; + PRUint32 retcount = 0; + + /* sanity check arguments */ + if ( !file || !dest || count == 0 || file->fpos >= file->fsize ) + return 0; + + /* Adjust amount to read if we're near EOF */ + if ( (file->fpos + count) > (PRUint32)file->fsize ) + count = file->fsize - file->fpos; + + + /* figure out how much of the data we want is already buffered */ + + startOffset = file->fpos - file->datastart; + endOffset = startOffset + count; + + if ( startOffset >= 0 && startOffset < file->datasize ) + { + /* The beginning of what we want is in the buffer */ + /* so copy as much as is available of what we want */ + + if ( endOffset <= file->datasize ) + bytesCopied = count; + else + bytesCopied = file->datasize - startOffset; + + memcpy( dest, file->data + startOffset, bytesCopied ); + retcount = bytesCopied; + file->fpos += bytesCopied; + + /* Was that all we wanted, or do we need to get more? */ + + leftover = count - bytesCopied; + PR_ASSERT( leftover >= 0 ); /* negative left? something's wrong! */ + + if ( leftover ) + { + /* need data that's not in the buffer */ + + /* if what's left fits in a buffer then load the buffer with the */ + /* new area before giving the data, otherwise just read right */ + /* into the user's dest buffer */ + + if ( _bufio_loadBuf( file, leftover ) ) + { + startOffset = file->fpos - file->datastart; + + /* we may not have been able to load as much as we wanted */ + if ( startOffset+leftover <= file->datasize ) + bytesRead = leftover; + else + bytesRead = file->datasize - startOffset; + + memcpy( dest+bytesCopied, file->data+startOffset, bytesRead ); + file->fpos += bytesRead; + retcount += bytesRead; + } + else + { + /* we need more than we could load into a buffer, so */ + /* skip buffering and just read the data directly */ + + if ( fseek( file->fd, file->fpos, SEEK_SET ) == 0 ) + { + bytesRead = fread(dest+bytesCopied, 1, leftover, file->fd); + file->fpos += bytesRead; + retcount += bytesRead; + } + else + { + /* XXX seek failed, couldn't load more data -- help! */ + /* should we call PR_SetError() ? */ + } + } + } + } + else + { + /* range doesn't start in the loaded buffer but it might end there */ + if ( endOffset > 0 && endOffset <= file->datasize ) + bytesCopied = endOffset; + else + bytesCopied = 0; + + leftover = count - bytesCopied; + + if ( bytesCopied ) + { + /* the tail end of the range we want is already buffered */ + /* first copy the buffered data to the dest area */ + memcpy( dest+leftover, file->data, bytesCopied ); + } + + /* now pick up the part that's not already in the buffer */ + + if ( _bufio_loadBuf( file, leftover ) ) + { + /* we were able to load some data */ + startOffset = file->fpos - file->datastart; + + /* we may not have been able to read as much as we wanted */ + if ( startOffset+leftover <= file->datasize ) + bytesRead = leftover; + else + bytesRead = file->datasize - startOffset; + + memcpy( dest, file->data+startOffset, bytesRead ); + } + else + { + /* leftover data doesn't fit so skip buffering */ + if ( fseek( file->fd, file->fpos, SEEK_SET ) == 0 ) + bytesRead = fread(dest, 1, leftover, file->fd); + else + bytesRead = 0; + } + + /* if we couldn't read all the leftover, don't tell caller */ + /* about the tail end we copied from the first buffer */ + if ( bytesRead == (PRUint32)leftover ) + retcount = bytesCopied + bytesRead; + else + retcount = bytesRead; + + file->fpos += retcount; + } + + return retcount; +} + + + +/** + * write through to disk skipping buffering. This will change + */ +PRUint32 bufio_Write(BufioFile* file, const char* src, PRUint32 count) +{ + PRInt32 startOffset; + PRInt32 endOffset; + PRUint32 retcount = 0; + PRUint32 bytesWritten = 0; + + /* sanity check arguments */ + if ( !file || !src || count == 0 || file->readOnly ) + return 0; + + /* Write to the current buffer if we can, otherwise load a new buffer */ + + startOffset = file->fpos - file->datastart; + endOffset = startOffset + count; + + if ( startOffset >= 0 && + startOffset < BUFIO_BUFSIZE && + endOffset <= BUFIO_BUFSIZE ) + { + /* the entire area we want to write is buffered */ + bytesWritten = count; + memcpy( file->data + startOffset, src, bytesWritten ); + file->bufdirty = PR_TRUE; + + if ( endOffset > file->datasize ) + file->datasize = endOffset; + + file->dirtystart = PR_MIN( startOffset, file->dirtystart ); + file->dirtyend = PR_MAX( endOffset, file->dirtyend ); + } + else if ( count > BUFIO_BUFSIZE ) + { + /* the data doesn't fit in a buffer, write w/out buffering. */ + + /* first check to see if it overlaps our current buffer */ + if ( startOffset < BUFIO_BUFSIZE && endOffset > 0 ) + { + /* this write overlaps at least part of the current buffer */ + + /* Flush any dirty data first */ + if ( file->bufdirty ) + _bufio_flushBuf( file ); + + /* then empty the buffer so stale data isn't used */ + file->datasize = 0; + file->dirtystart = BUFIO_BUFSIZE; + file->dirtyend = 0; + } + + /* now if is safe to do the write */ + if ( fseek( file->fd, file->fpos, SEEK_SET ) == 0 ) + { + bytesWritten = fwrite( src, 1, count, file->fd ); + } + } + else + { + /* the data doesn't fit in the current buffer, so we'll just */ + /* start a new buffer. Flush any dirty data first */ + if ( file->bufdirty ) + _bufio_flushBuf( file ); + + bytesWritten = count; + memcpy( file->data, src, bytesWritten ); + file->bufdirty = PR_TRUE; + file->datastart = file->fpos; /* NB: original fpos! */ + file->datasize = bytesWritten; + file->dirtystart = 0; + file->dirtyend = file->datasize; + } + + file->fpos += bytesWritten; + if ( file->fpos > file->fsize ) + { + file->fsize = file->fpos; + } + + return bytesWritten; +} + + + +int bufio_Flush(BufioFile* file) +{ + if ( file->bufdirty ) + _bufio_flushBuf( file ); + + return fflush(file->fd); +} + + + +/*---------------------------------------------------------------------------* + * internal helper functions + *---------------------------------------------------------------------------*/ +/** + * Attempts to load the buffer with the requested amount of data. + * Returns PR_TRUE if it was able to load *some* of the requested + * data, but not necessarily all. Returns PR_FALSE if the read fails + * or if the requested amount wouldn't fit in the buffer. + */ +static PRBool _bufio_loadBuf( BufioFile* file, PRUint32 count ) +{ + PRInt32 startBuf; + PRInt32 endPos; + PRInt32 endBuf; + PRUint32 bytesRead; + + /* no point in buffering more than the physical buffer will hold */ + if ( count > BUFIO_BUFSIZE ) + return PR_FALSE; + + /* Is caller asking for data we already have? */ + if ( STARTS_IN_BUF(file) && ENDS_IN_BUF(file,count) ) + { + PR_ASSERT(0); + return PR_TRUE; + } + + /* if the buffer's dirty make sure we successfully flush it */ + if ( file->bufdirty && _bufio_flushBuf(file) != 0 ) + return PR_FALSE; + + /* For now we're not trying anything smarter than simple paging. */ + /* Slide over if necessary to fit the entire request */ + startBuf = ( file->fpos / BUFIO_BUFSIZE ) * BUFIO_BUFSIZE; + endPos = file->fpos + count; + endBuf = startBuf + BUFIO_BUFSIZE; + if ( endPos > endBuf ) + startBuf += (endPos - endBuf); + + if ( fseek( file->fd, startBuf, SEEK_SET ) != 0 ) + return PR_FALSE; + else + { + bytesRead = fread( file->data, 1, BUFIO_BUFSIZE, file->fd ); + if (bytesRead) + { + file->datastart = startBuf; + file->datasize = bytesRead; + file->bufdirty = PR_FALSE; + file->dirtystart = BUFIO_BUFSIZE; + file->dirtyend = 0; + } + + /* return true if we got *any* of the requested data */ + if ( bytesRead > (PRUint32)(file->fpos - startBuf) ) + return PR_TRUE; + else + return PR_FALSE; + } +} + + + +static int _bufio_flushBuf( BufioFile* file ) +{ + PRUint32 written; + PRUint32 dirtyamt; + PRInt32 startpos; + + PR_ASSERT(file); + if ( !file || !file->bufdirty ) + return 0; + + startpos = file->datastart + file->dirtystart; + if ( !fseek( file->fd, startpos, SEEK_SET ) ) + { + dirtyamt = file->dirtyend - file->dirtystart; + written = fwrite( file->data+file->dirtystart, 1, dirtyamt, file->fd ); + if ( written == dirtyamt ) + return 0; + } + return -1; +} + +/* EOF nr_bufio.c */ diff --git a/mozilla/modules/libreg/src/nr_bufio.h b/mozilla/modules/libreg/src/nr_bufio.h new file mode 100644 index 00000000000..4e262d16d59 --- /dev/null +++ b/mozilla/modules/libreg/src/nr_bufio.h @@ -0,0 +1,46 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator + * + * The Initial Developer of the Original Code is Netscape Communications + * Corporation. Portions created by Netscape are + * Copyright (C) 1999 Netscape Communications Corporation. All Rights + * Reserved. + * + * Contributors: + * Daniel Veditz + */ + +/* nr_bufio.h + * Buffered I/O routines to improve registry performance + * + * the routines mirror fopen(), fclose() et al + * + * __NOTE__: the filenames are *native* filenames, not NSPR names. + */ + +#ifndef _NR_BUFIO_H_ +#define _NR_BUFIO_H_ + +typedef struct BufioFileStruct BufioFile; + +BufioFile* bufio_Open(const char* name, const char* mode); +int bufio_Close(BufioFile* file); +int bufio_Seek(BufioFile* file, PRInt32 offset, int whence); +PRUint32 bufio_Read(BufioFile* file, char* dest, PRUint32 count); +PRUint32 bufio_Write(BufioFile* file, const char* src, PRUint32 count); +PRInt32 bufio_Tell(BufioFile* file); +int bufio_Flush(BufioFile* file); + +#endif /* _NR_BUFIO_H_ */ + diff --git a/mozilla/modules/libreg/src/reg.c b/mozilla/modules/libreg/src/reg.c index e29cba57c61..892efb9cf8a 100644 --- a/mozilla/modules/libreg/src/reg.c +++ b/mozilla/modules/libreg/src/reg.c @@ -35,8 +35,8 @@ /* Preprocessor Defines * STANDALONE_REGISTRY - define if not linking with Navigator - * NOCACHE_HDR - define if multi-threaded access to registry - * SELF_REPAIR - define to skip header update on open + * NOCACHE_HDR - define if multi-process access to registry + * SELF_REPAIR - undefine to skip header update on open * VERIFY_READ - define TRUE to double-check short reads * #define NOCACHE_HDR 1 @@ -51,7 +51,6 @@ #ifdef STANDALONE_REGISTRY #include -#include #include #include @@ -74,16 +73,6 @@ #include "reg.h" #include "NSReg.h" -#if !defined(STANDALONE_REGISTRY) && defined(SEEK_SET) - /* Undo the damage caused by xp_core.h, which is included by NSReg.h */ - #undef SEEK_SET - #undef SEEK_CUR - #undef SEEK_END - #define SEEK_SET PR_SEEK_SET - #define SEEK_CUR PR_SEEK_CUR - #define SEEK_END PR_SEEK_END -#endif - #if defined(XP_UNIX) #ifndef MAX_PATH #define MAX_PATH 1024 @@ -384,20 +373,26 @@ static REGERR nr_OpenFile(char *path, FILEHANDLE *fh) PR_ASSERT( fh != NULL ); /* Open the file for exclusive random read/write */ - (*fh) = XP_FileOpen(path, PR_RDWR|PR_CREATE_FILE, 00644); + *fh = XP_FileOpen(path, XP_FILE_UPDATE_BIN); + if ( !VALID_FILEHANDLE(*fh) ) { switch (PR_GetError()) { - case PR_FILE_NOT_FOUND_ERROR: /* file not found */ - return REGERR_NOFILE; + case PR_FILE_NOT_FOUND_ERROR: + /* file not found, try to create it */ + *fh = XP_FileOpen(path, XP_FILE_TRUNCATE_BIN); + if ( VALID_FILEHANDLE(*fh) ) + return REGERR_OK; + else + return REGERR_NOFILE; case PR_FILE_IS_BUSY_ERROR: /* file in use */ case PR_FILE_IS_LOCKED_ERROR: case PR_ILLEGAL_ACCESS_ERROR: case PR_NO_ACCESS_RIGHTS_ERROR: /* try read only */ - (*fh) = XP_FileOpen(path, PR_RDONLY, 00644); + (*fh) = XP_FileOpen(path, XP_FILE_READ_BIN); if ( VALID_FILEHANDLE(*fh) ) return REGERR_READONLY; else @@ -472,7 +467,7 @@ static REGERR nr_ReadFile(FILEHANDLE fh, REGOFF offset, int32 len, void *buffer) /* If buffer has new data beyond what PR_READ() says it got */ /* we'll assume the read was OK--this is a gamble but */ /* missing errors will cause fewer problems than too many. */ - p = (unsigned char*)buffer+readlen; + p = (unsigned char*)buffer + readlen; while ( (*p == (unsigned char)FILLCHAR) && (p < dbgend) ) { p++; } @@ -1239,14 +1234,6 @@ static REGERR nr_CatName(REGFILE *reg, REGOFF node, char *path, uint32 bufsize, REGDESC *desc); static REGERR nr_ReplaceName(REGFILE *reg, REGOFF node, char *path, uint32 bufsize, REGDESC *desc); - -#if 0 /* old interface */ -static char * nr_LastDelim(char *pPath); -static XP_Bool nr_IsQualifiedEntry(char *pPath); -static REGERR nr_SplitEntry(char *pPath, char **name, char **value); -static REGERR nr_CatNameValue(char *path, int bufsize, REGDESC *desc); -static REGERR nr_ReplaceNameValue(char *path, int bufsize, REGDESC *desc); -#endif /* -------------------------------------------------------------------- */ @@ -1694,111 +1681,6 @@ static REGERR nr_CreateEntry(REGFILE *reg, REGDESC *pParent, char *name, -#if 0 /* old interface */ -VR_INTERFACE(REGERR) NR_RegRename(RKEY key, char *path, char *newname) -{ - - REGDESC desc; - REGERR err; - - if ( !VALID_FILEHANDLE(gReg.fh) ) - return REGERR_FAIL; - - /* Okay to Update to "", but names must not be null */ - if (!newname || !*newname) - return REGERR_PARAM; - - err = nr_Lock(&gReg); - if (err != REGERR_OK) - return err; - - /* Find the key or entry to rename (and validate the - incoming parameters) */ - err = nr_Find((REGOFF)key, path, &desc, 0, 0, FALSE); - if (err != REGERR_OK) - goto cleanup; - - /* Write the new name string to the file and update - the key or entry's pointer */ - err = nr_AppendName(&gReg, newname, &desc); - if (err != REGERR_OK) - goto cleanup; - - /* Write the key or entry back to the disk and return */ - err = nr_WriteDesc(&gReg, &desc); - -cleanup: - nr_Unlock(&gReg); - return err; - -} /* RegRename */ - - - -VR_INTERFACE(REGERR) NR_RegPack(char *newfilename) -{ - - REGFILE dstReg; - char *path = NULL; - int err = REGERR_OK; - - dstReg.fh = NULL; - - if (!newfilename || !*newfilename) - return REGERR_PARAM; - if ( !VALID_FILEHANDLE(gReg.fh) ) - return REGERR_FAIL; - - /* open it & create a header by trying to read */ - err = nr_OpenFile(newfilename, &dstReg.fh); - if (err != REGERR_OK) - goto cleanup; - err = nr_ReadHdr(&dstReg); - if (err != REGERR_OK) - goto cleanup; - - /* read records from the current registry file and - add them to 'dstReg' */ - path = XP_ALLOC(PACKBUFFERSIZE); - if (path == NULL) - { - err = REGERR_FAIL; - goto cleanup; - } - - XP_STRCPY(path, "/"); - - err = nr_Lock(&gReg); - if (err != REGERR_OK) - goto cleanup; - - while (NR_RegNext( 0, PACKBUFFERSIZE, path ) == REGERR_OK) - { - err = nr_RegGenericAdd(&dstReg, 0, path); - if (err != REGERR_OK) - break; - } - - nr_Unlock(&gReg); - -cleanup: - XP_FREEIF(path); - if ( VALID_FILEHANDLE(dstReg.fh) ) - { - /* even if not caching headers it could be dirty due to an error */ - if (dstReg.hdrDirty) { - nr_WriteHdr(&dstReg); - } - nr_CloseFile(&dstReg.fh); - } - - return err; - -} /* RegPack */ - -#endif /* old interface */ - - /* --------------------------------------------------------------------- * Intermediate API @@ -3356,8 +3238,10 @@ VR_INTERFACE(REGERR) NR_RegEnumSubkeys( HREG hReg, RKEY key, REGENUM *state, key = nr_TranslateKey( reg, key ); if ( key == 0 ) err = REGERR_PARAM; - else + else if ( *state == 0 ) err = nr_ReadDesc( reg, key, &desc); + else + err = REGERR_OK; if ( err == REGERR_OK ) { @@ -3750,6 +3634,7 @@ static REGERR nr_addNodesToNewReg( HREG hReg, RKEY rootkey, HREG hRegNew, void * } + /* --------------------------------------------------------------------- * NR_RegPack - Pack an open registry. * Registry is locked the entire time. @@ -3760,6 +3645,8 @@ static REGERR nr_addNodesToNewReg( HREG hReg, RKEY rootkey, HREG hRegNew, void * */ VR_INTERFACE(REGERR) NR_RegPack( HREG hReg, void *userData, nr_RegPackCallbackFunc fn) { + return REGERR_FAIL; /* XXX resurrect after mozilla beta 1 */ +#if RESURRECT_LATER XP_File fh; REGFILE* reg; HREG hRegTemp; @@ -3860,9 +3747,10 @@ safe_exit: PR_Unlock( reglist_lock ); nr_Unlock(reg); return err; - +#endif /* RESURRECT_LATER */ } + #ifdef XP_MAC #pragma export reset #endif diff --git a/mozilla/modules/libreg/src/vr_stubs.h b/mozilla/modules/libreg/src/vr_stubs.h index f99a061bb23..82b7b4c2112 100644 --- a/mozilla/modules/libreg/src/vr_stubs.h +++ b/mozilla/modules/libreg/src/vr_stubs.h @@ -81,20 +81,7 @@ #ifdef STANDALONE_REGISTRY -#define XP_FILE_READ "r" -#define XP_FILE_READ_BIN "rb" -#define XP_FILE_WRITE "w" -#define XP_FILE_WRITE_BIN "wb" -#define XP_FILE_UPDATE "r+" -#define XP_FILE_TRUNCATE "w+" -#ifdef SUNOS4 -/* XXX SunOS4 hack -- make this universal by using r+b and w+b */ -#define XP_FILE_UPDATE_BIN "r+" -#define XP_FILE_TRUNCATE_BIN "w+" -#else -#define XP_FILE_UPDATE_BIN "rb+" -#define XP_FILE_TRUNCATE_BIN "wb+" -#endif +#define USE_STDIO_MODES #define XP_FileSeek(file,offset,whence) fseek((file), (offset), (whence)) #define XP_FileRead(dest,count,file) fread((dest), 1, (count), (file)) @@ -132,29 +119,19 @@ typedef FILE * XP_File; -#else /* if not standalone, use NSPR */ +#else /* not standalone, use NSPR */ -#define XP_FILE_READ PR_RDONLY, 0644 -#define XP_FILE_READ_BIN PR_RDONLY, 0644 -#define XP_FILE_WRITE PR_WRONLY, 0644 -#define XP_FILE_WRITE_BIN PR_WRONLY, 0644 -#define XP_FILE_UPDATE PR_RDWR|PR_CREATE_FILE, 0644 -#define XP_FILE_TRUNCATE (PR_WRONLY | PR_TRUNCATE), 0644 - -#define XP_FILE_UPDATE_BIN PR_RDWR|PR_CREATE_FILE, 0644 -#define XP_FILE_TRUNCATE_BIN (PR_RDWR | PR_TRUNCATE), 0644 - -#ifdef SEEK_SET - #undef SEEK_SET - #undef SEEK_CUR - #undef SEEK_END - #define SEEK_SET PR_SEEK_SET - #define SEEK_CUR PR_SEEK_CUR - #define SEEK_END PR_SEEK_END -#endif +/*-------------------------------------*/ +/* Alternate fileI/O function mappings */ +/*-------------------------------------*/ #if USE_MMAP_REGISTRY_IO + /*-----------------------------------------------*/ + /* NSPR mememory-mapped I/O (write through) */ + /* unfortunately this isn't supported on the Mac */ + /*-----------------------------------------------*/ +#define USE_NSPR_MODES #include "mmapio.h" #define XP_FileSeek(file,offset,whence) mmio_FileSeek((file),(offset),(whence)) @@ -162,12 +139,36 @@ typedef FILE * XP_File; #define XP_FileWrite(src,count,file) mmio_FileWrite((file), (src), (count)) #define XP_FileTell(file) mmio_FileTell(file) #define XP_FileClose(file) mmio_FileClose(file) -#define XP_FileOpen(path, flags, mode) mmio_FileOpen((path), (flags), (mode)) +#define XP_FileOpen(path, mode) mmio_FileOpen((path), mode ) #define XP_FileFlush(file) ((void)1) typedef MmioFile* XP_File; -#else /*USE_MMAP_REGISTRY_IO*/ +#elif USE_BUFFERED_REGISTRY_IO + /*-----------------------------------------------*/ + /* home-grown XP buffering */ + /* writes are buffered too so use flush! */ + /*-----------------------------------------------*/ +#define USE_STDIO_MODES + +#include "nr_bufio.h" +#define XP_FileSeek(file,offset,whence) bufio_Seek((file),(offset),(whence)) +#define XP_FileRead(dest,count,file) bufio_Read((file), (dest), (count)) +#define XP_FileWrite(src,count,file) bufio_Write((file), (src), (count)) +#define XP_FileTell(file) bufio_Tell(file) +#define XP_FileClose(file) bufio_Close(file) +#define XP_FileOpen(path, mode) bufio_Open((path), (mode)) +#define XP_FileFlush(file) ((void)1) + + + +typedef BufioFile* XP_File; + +#else + /*-----------------------------------------------*/ + /* standard NSPR file I/O */ + /*-----------------------------------------------*/ +#define USE_NSPR_MODES /* ** Note that PR_Seek returns the offset (if successful) and -1 otherwise. So ** to make this code work @@ -178,7 +179,7 @@ typedef MmioFile* XP_File; #define XP_FileRead(dest,count,file) PR_Read((file), (dest), (count)) #define XP_FileWrite(src,count,file) PR_Write((file), (src), (count)) #define XP_FileTell(file) PR_Seek(file, 0, PR_SEEK_CUR) -#define XP_FileOpen(path, flags, mode) PR_Open((path), (flags), (mode)) +#define XP_FileOpen(path, mode) PR_Open((path), mode ) #define XP_FileClose(file) PR_Close(file) #ifdef XP_MAC #define XP_FileFlush(file) PR_Sync(file) @@ -190,6 +191,8 @@ typedef PRFileDesc* XP_File; #endif /*USE_MMAP_REGISTRY_IO*/ + + #define XP_ASSERT(x) PR_ASSERT((x)) #define XP_STRCAT(a,b) PL_strcat((a),(b)) @@ -212,19 +215,59 @@ typedef PRFileDesc* XP_File; #endif /*STANDALONE_REGISTRY*/ + +/*--- file open modes for stdio ---*/ +#ifdef USE_STDIO_MODES +#define XP_FILE_READ "r" +#define XP_FILE_READ_BIN "rb" +#define XP_FILE_WRITE "w" +#define XP_FILE_WRITE_BIN "wb" +#define XP_FILE_UPDATE "r+" +#define XP_FILE_TRUNCATE "w+" +#ifdef SUNOS4 +/* XXX SunOS4 hack -- make this universal by using r+b and w+b */ +#define XP_FILE_UPDATE_BIN "r+" +#define XP_FILE_TRUNCATE_BIN "w+" +#else +#define XP_FILE_UPDATE_BIN "rb+" +#define XP_FILE_TRUNCATE_BIN "wb+" +#endif +#endif /* USE_STDIO_MODES */ + +/*--- file open modes for NSPR file I/O ---*/ +#ifdef USE_NSPR_MODES +#define XP_FILE_READ PR_RDONLY, 0644 +#define XP_FILE_READ_BIN PR_RDONLY, 0644 +#define XP_FILE_WRITE PR_WRONLY, 0644 +#define XP_FILE_WRITE_BIN PR_WRONLY, 0644 +#define XP_FILE_UPDATE (PR_RDWR|PR_CREATE_FILE), 0644 +#define XP_FILE_TRUNCATE (PR_RDWR | PR_TRUNCATE), 0644 + +#define XP_FILE_UPDATE_BIN PR_RDWR|PR_CREATE_FILE, 0644 +#define XP_FILE_TRUNCATE_BIN (PR_RDWR | PR_TRUNCATE), 0644 + +#ifdef SEEK_SET + #undef SEEK_SET + #undef SEEK_CUR + #undef SEEK_END + #define SEEK_SET PR_SEEK_SET + #define SEEK_CUR PR_SEEK_CUR + #define SEEK_END PR_SEEK_END +#endif +#endif /* USE_NSPR_MODES */ + + + + + #ifdef STANDALONE_REGISTRY /* included from prmon.h otherwise */ #include "prtypes.h" #endif /*STANDALONE_REGISTRY*/ typedef int XP_Bool; -#ifdef XP_PC - typedef struct _stat XP_StatStruct; - #define XP_Stat(file,data,type) _stat((file),(data)) -#else - typedef struct stat XP_StatStruct; - #define XP_Stat(file,data,type) stat((file),(data)) -#endif /*XP_PC*/ +typedef struct stat XP_StatStruct; +#define XP_Stat(file,data) stat((file),(data)) #ifdef XP_MAC extern int nr_RenameFile(char *from, char *to);