Bug 592422 - preallocate individual (non-block) cache files. r=jduell a=blocking-bN
authorMichal Novotny <michal.novotny@gmail.com>
Wed, 24 Nov 2010 16:42:30 +0100
changeset 58167 59144b59cd11dc99985b669e348a55a68be4fee8
parent 58166 2c8654b57cca8c10e9afef8dd2ac5fd05f38dd3f
child 58168 6852e7c47edf9f467aa133bd3851d6792b7b5d1d
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersjduell, blocking-bN
bugs592422
milestone2.0b8pre
Bug 592422 - preallocate individual (non-block) cache files. r=jduell a=blocking-bN
netwerk/cache/nsDiskCacheMap.h
netwerk/cache/nsDiskCacheStreams.cpp
xpcom/glue/FileUtils.cpp
--- a/netwerk/cache/nsDiskCacheMap.h
+++ b/netwerk/cache/nsDiskCacheMap.h
@@ -89,16 +89,19 @@ struct nsDiskCacheEntry;
 // Min and max values for the number of records in the DiskCachemap
 #define kMinRecordCount    512
 
 #define kSeparateFile      0
 // #define must always  be <= 65535KB, or overflow. See bug 443067 Comment 8
 #define kMaxDataFileSize   5 * 1024 * 1024  // 5 MB (in bytes) 
 #define kBuckets           (1 << 5)    // must be a power of 2!
 
+// preallocate up to 1MB of separate cache file
+#define kPreallocateLimit  1 * 1024 * 1024
+
 class nsDiskCacheRecord {
 
 private:
     PRUint32    mHashNumber;
     PRUint32    mEvictionRank;
     PRUint32    mDataLocation;
     PRUint32    mMetaLocation;
  
--- a/netwerk/cache/nsDiskCacheStreams.cpp
+++ b/netwerk/cache/nsDiskCacheStreams.cpp
@@ -38,16 +38,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 
 #include "nsDiskCache.h"
 #include "nsDiskCacheDevice.h"
 #include "nsDiskCacheStreams.h"
 #include "nsCacheService.h"
+#include "mozilla/FileUtils.h"
 
 
 
 // Assumptions:
 //      - cache descriptors live for life of streams
 //      - streams will only be used by FileTransport,
 //         they will not be directly accessible to clients
 //      - overlapped I/O is NOT supported
@@ -724,16 +725,20 @@ nsDiskCacheStreamIO::FlushBufferToFile()
             rv = cacheMap->DeleteStorage(record, nsDiskCache::kData);
             if (NS_FAILED(rv))  return rv;
         }
         record->SetDataFileGeneration(mBinding->mGeneration);
         
         // allocate file
         rv = OpenCacheFile(PR_RDWR | PR_CREATE_FILE, &mFD);
         if (NS_FAILED(rv))  return rv;
+
+        PRInt64 dataSize = mBinding->mCacheEntry->PredictedDataSize();
+        if (dataSize != -1)
+            mozilla::fallocate(mFD, PR_MIN(dataSize, kPreallocateLimit));
     }
     
     // write buffer
     PRInt32 bytesWritten = PR_Write(mFD, mBuffer, mBufEnd);
     if (PRUint32(bytesWritten) != mBufEnd) {
         NS_WARNING("failed to flush all data");
         return NS_ERROR_UNEXPECTED;     // NS_ErrorAccordingToNSPR()
     }
--- a/xpcom/glue/FileUtils.cpp
+++ b/xpcom/glue/FileUtils.cpp
@@ -42,66 +42,83 @@
 #include <sys/stat.h>
 #elif defined(XP_WIN)
 #include <windows.h>
 #endif
 
 #include "nscore.h"
 #include "private/pprio.h"
 #include "mozilla/FileUtils.h"
+#include "mozilla/FunctionTimer.h"
 
 bool 
 mozilla::fallocate(PRFileDesc *aFD, PRInt64 aLength) 
 {
+  NS_TIME_FUNCTION;
 #if defined(HAVE_POSIX_FALLOCATE)
   return posix_fallocate(PR_FileDesc2NativeHandle(aFD), 0, aLength) == 0;
 #elif defined(XP_WIN)
-  return PR_Seek64(aFD, aLength, PR_SEEK_SET) == aLength
-    && 0 != SetEndOfFile((HANDLE)PR_FileDesc2NativeHandle(aFD));
+  PROffset64 oldpos = PR_Seek64(aFD, 0, PR_SEEK_CUR);
+  if (oldpos == -1)
+    return false;
+
+  if (PR_Seek64(aFD, aLength, PR_SEEK_SET) != aLength)
+    return false;
+
+  bool retval = (0 != SetEndOfFile((HANDLE)PR_FileDesc2NativeHandle(aFD)));
+
+  PR_Seek64(aFD, oldpos, PR_SEEK_SET);
+  return retval;
 #elif defined(XP_MACOSX)
   int fd = PR_FileDesc2NativeHandle(aFD);
   fstore_t store = {F_ALLOCATECONTIG, F_PEOFPOSMODE, 0, aLength};
   // Try to get a continous chunk of disk space
   int ret = fcntl(fd, F_PREALLOCATE, &store);
-	if(-1 == ret){
+  if (-1 == ret) {
     // OK, perhaps we are too fragmented, allocate non-continuous
     store.fst_flags = F_ALLOCATEALL;
     ret = fcntl(fd, F_PREALLOCATE, &store);
     if (-1 == ret)
       return false;
   }
   return 0 == ftruncate(fd, aLength);
 #elif defined(XP_UNIX)
   // The following is copied from fcntlSizeHint in sqlite
   /* If the OS does not have posix_fallocate(), fake it. First use
   ** ftruncate() to set the file size, then write a single byte to
   ** the last byte in each block within the extended region. This
   ** is the same technique used by glibc to implement posix_fallocate()
   ** on systems that do not have a real fallocate() system call.
   */
+  PROffset64 oldpos = PR_Seek64(aFD, 0, PR_SEEK_CUR);
+  if (oldpos == -1)
+    return false;
+
   struct stat buf;
   int fd = PR_FileDesc2NativeHandle(aFD);
   if (fstat(fd, &buf))
     return false;
 
   if (buf.st_size >= aLength)
     return false;
 
   const int nBlk = buf.st_blksize;
 
   if (!nBlk)
     return false;
 
   if (ftruncate(fd, aLength))
     return false;
-  
+
   int nWrite; // Return value from write()
   PRInt64 iWrite = ((buf.st_size + 2 * nBlk - 1) / nBlk) * nBlk - 1; // Next offset to write to
   do {
     nWrite = 0;
     if (PR_Seek64(aFD, iWrite, PR_SEEK_SET) == iWrite)
       nWrite = PR_Write(aFD, "", 1);
     iWrite += nBlk;
   } while (nWrite == 1 && iWrite < aLength);
+
+  PR_Seek64(aFD, oldpos, PR_SEEK_SET);
   return nWrite == 1;
 #endif
   return false;
 }