Bug 988816 - Allow to keep file descriptor in JAR cache. r=aklotz, jduell
authorShian-Yow Wu <swu@mozilla.com>
Fri, 18 Jul 2014 10:46:24 +0800
changeset 208623 f7de657a37ed109072f19e1dffe4867f856a5047
parent 208622 8912d2088eee28737b418afd8cd1e246fc97c6e7
child 208624 a5446bb5fa7d082fb022af063811343a57f15376
push idunknown
push userunknown
push dateunknown
reviewersaklotz, jduell
bugs988816
milestone33.0a1
Bug 988816 - Allow to keep file descriptor in JAR cache. r=aklotz, jduell
modules/libjar/nsIZipReader.idl
modules/libjar/nsJAR.cpp
modules/libjar/nsJAR.h
modules/libjar/nsJARChannel.cpp
modules/libjar/nsZipArchive.cpp
modules/libjar/nsZipArchive.h
netwerk/ipc/RemoteOpenFileChild.cpp
netwerk/ipc/RemoteOpenFileChild.h
--- a/modules/libjar/nsIZipReader.idl
+++ b/modules/libjar/nsIZipReader.idl
@@ -1,16 +1,22 @@
 /* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  *
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
+%{C++
+struct PRFileDesc;
+%}
+
+[ptr] native PRFileDescStar(PRFileDesc);
+
 interface nsIUTF8StringEnumerator;
 interface nsIInputStream;
 interface nsIFile;
 interface nsICertificatePrincipal;
 
 [scriptable, uuid(fad6f72f-13d8-4e26-9173-53007a4afe71)]
 interface nsIZipEntry : nsISupports
 {
@@ -187,17 +193,17 @@ interface nsIZipReader : nsISupports
     nsICertificatePrincipal getCertificatePrincipal(in AUTF8String aEntryName);   
     
     readonly attribute uint32_t manifestEntriesCount;
 };
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsIZipReaderCache
 
-[scriptable, uuid(748050ac-3ab6-4472-bc2a-cb1564ac6a81)]
+[scriptable, uuid(94ecd586-d405-4801-93d3-8ac7bef81bde)]
 interface nsIZipReaderCache : nsISupports
 {
     /**
      * Initializes a new zip reader cache. 
      * @param cacheSize - the number of released entries to maintain before
      *   beginning to throw some out (note that the number of outstanding
      *   entries can be much greater than this number -- this is the count
      *   for those otherwise unused entries)
@@ -223,16 +229,30 @@ interface nsIZipReaderCache : nsISupport
     bool isCached(in nsIFile zipFile);
 
     /**
      * Returns a (possibly shared) nsIZipReader for a zip inside another zip
      *
      * See getZip
      */
     nsIZipReader getInnerZip(in nsIFile zipFile, in AUTF8String zipEntry);
+
+    /**
+     * Whether to keep NSPR file descriptor for newly opened files in the cache.
+     * When aMustCacheFd is enabled and a file is given, the file will be flushed
+     * from the cache if its file descriptor was not cached.
+     * Note: currently not supported on Windows platform.
+     */
+    void setMustCacheFd(in nsIFile zipFile, in bool aMustCacheFd);
+
+    /**
+     * Returns the cached NSPR file descriptor of the file.
+     * Note: currently not supported on Windows platform.
+     */
+    PRFileDescStar getFd(in nsIFile zipFile);
 };
 
 ////////////////////////////////////////////////////////////////////////////////
 
 %{C++
 
 #define NS_ZIPREADER_CID                             \
 { /* 88e2fd0b-f7f4-480c-9483-7846b00e8dad */         \
--- a/modules/libjar/nsJAR.cpp
+++ b/modules/libjar/nsJAR.cpp
@@ -136,17 +136,17 @@ nsJAR::Open(nsIFile* zipFile)
 
   // The omnijar is special, it is opened early on and closed late
   // this avoids reopening it
   nsRefPtr<nsZipArchive> zip = mozilla::Omnijar::GetReader(zipFile);
   if (zip) {
     mZip = zip;
     return NS_OK;
   }
-  return mZip->OpenArchive(zipFile);
+  return mZip->OpenArchive(zipFile, mCache ? mCache->IsMustCacheFdEnabled() : false);
 }
 
 NS_IMETHODIMP
 nsJAR::OpenInner(nsIZipReader *aZipReader, const nsACString &aZipEntry)
 {
   NS_ENSURE_ARG_POINTER(aZipReader);
   if (mOpened) return NS_ERROR_FAILURE; // Already open!
 
@@ -386,16 +386,36 @@ nsJAR::GetManifestEntriesCount(uint32_t*
 nsresult
 nsJAR::GetJarPath(nsACString& aResult)
 {
   NS_ENSURE_ARG_POINTER(mZipFile);
 
   return mZipFile->GetNativePath(aResult);
 }
 
+nsresult
+nsJAR::GetNSPRFileDesc(PRFileDesc** aNSPRFileDesc)
+{
+  if (!aNSPRFileDesc) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  *aNSPRFileDesc = nullptr;
+
+  if (!mZip) {
+    return NS_ERROR_FAILURE;
+  }
+
+  nsRefPtr<nsZipHandle> handle = mZip->GetFD();
+  if (!handle) {
+    return NS_ERROR_FAILURE;
+  }
+
+  return handle->GetNSPRFileDesc(aNSPRFileDesc);
+}
+
 //----------------------------------------------
 // nsJAR private implementation
 //----------------------------------------------
 nsresult
 nsJAR::LoadEntry(const nsACString &aFilename, char** aBuf, uint32_t* aBufLen)
 {
   //-- Get a stream for reading the file
   nsresult rv;
@@ -1004,16 +1024,17 @@ nsJARItem::GetPermissions(uint32_t* aPer
 ////////////////////////////////////////////////////////////////////////////////
 // nsIZipReaderCache
 
 NS_IMPL_ISUPPORTS(nsZipReaderCache, nsIZipReaderCache, nsIObserver, nsISupportsWeakReference)
 
 nsZipReaderCache::nsZipReaderCache()
   : mLock("nsZipReaderCache.mLock")
   , mZips(16)
+  , mMustCacheFd(false)
 #ifdef ZIP_CACHE_HIT_RATE
     ,
     mZipCacheLookups(0),
     mZipCacheHits(0),
     mZipCacheFlushes(0),
     mZipSyncMisses(0)
 #endif
 {
@@ -1099,17 +1120,16 @@ nsZipReaderCache::GetZip(nsIFile* zipFil
   if (zip) {
 #ifdef ZIP_CACHE_HIT_RATE
     mZipCacheHits++;
 #endif
     zip->ClearReleaseTime();
   } else {
     zip = new nsJAR();
     zip->SetZipReaderCache(this);
-
     rv = zip->Open(zipFile);
     if (NS_FAILED(rv)) {
       return rv;
     }
 
     MOZ_ASSERT(!mZips.Contains(uri));
     mZips.Put(uri, zip);
   }
@@ -1157,16 +1177,97 @@ nsZipReaderCache::GetInnerZip(nsIFile* z
 
     MOZ_ASSERT(!mZips.Contains(uri));
     mZips.Put(uri, zip);
   }
   zip.forget(result);
   return rv;
 }
 
+NS_IMETHODIMP
+nsZipReaderCache::SetMustCacheFd(nsIFile* zipFile, bool aMustCacheFd)
+{
+#if defined(XP_WIN)
+  MOZ_CRASH("Not implemented");
+  return NS_ERROR_NOT_IMPLEMENTED;
+#else
+  mMustCacheFd = aMustCacheFd;
+
+  if (!aMustCacheFd) {
+    return NS_OK;
+  }
+
+  if (!zipFile) {
+    return NS_ERROR_FAILURE;
+  }
+
+  nsresult rv;
+  nsAutoCString uri;
+  rv = zipFile->GetNativePath(uri);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  uri.Insert(NS_LITERAL_CSTRING("file:"), 0);
+
+  MutexAutoLock lock(mLock);
+  nsRefPtr<nsJAR> zip;
+  mZips.Get(uri, getter_AddRefs(zip));
+  if (!zip) {
+    return NS_ERROR_FAILURE;
+  }
+
+  // Flush the file from the cache if its file descriptor was not cached.
+  PRFileDesc* fd = nullptr;
+  zip->GetNSPRFileDesc(&fd);
+  if (!fd) {
+#ifdef ZIP_CACHE_HIT_RATE
+    mZipCacheFlushes++;
+#endif
+    zip->SetZipReaderCache(nullptr);
+    mZips.Remove(uri);
+  }
+  return NS_OK;
+#endif /* XP_WIN */
+}
+
+NS_IMETHODIMP
+nsZipReaderCache::GetFd(nsIFile* zipFile, PRFileDesc** aRetVal)
+{
+#if defined(XP_WIN)
+  MOZ_CRASH("Not implemented");
+  return NS_ERROR_NOT_IMPLEMENTED;
+#else
+  if (!zipFile) {
+    return NS_ERROR_FAILURE;
+  }
+
+  nsresult rv;
+  nsAutoCString uri;
+  rv = zipFile->GetNativePath(uri);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  uri.Insert(NS_LITERAL_CSTRING("file:"), 0);
+
+  MutexAutoLock lock(mLock);
+  nsRefPtr<nsJAR> zip;
+  mZips.Get(uri, getter_AddRefs(zip));
+  if (!zip) {
+    return NS_ERROR_FAILURE;
+  }
+
+  zip->ClearReleaseTime();
+  rv = zip->GetNSPRFileDesc(aRetVal);
+  // Do this to avoid possible deadlock on mLock with ReleaseZip().
+  MutexAutoUnlock unlock(mLock);
+  nsRefPtr<nsJAR> zipTemp = zip.forget();
+  return rv;
+#endif /* XP_WIN */
+}
+
 static PLDHashOperator
 FindOldestZip(const nsACString &aKey, nsJAR* aZip, void* aClosure)
 {
   nsJAR** oldestPtr = static_cast<nsJAR**>(aClosure);
   nsJAR* oldest = *oldestPtr;
   nsJAR* current = aZip;
   PRIntervalTime currentReleaseTime = current->GetReleaseTime();
   if (currentReleaseTime != PR_INTERVAL_NO_TIMEOUT) {
--- a/modules/libjar/nsJAR.h
+++ b/modules/libjar/nsJAR.h
@@ -90,16 +90,18 @@ class nsJAR : public nsIZipReader
     void ClearReleaseTime() {
       mReleaseTime = PR_INTERVAL_NO_TIMEOUT;
     }
 
     void SetZipReaderCache(nsZipReaderCache* cache) {
       mCache = cache;
     }
 
+    nsresult GetNSPRFileDesc(PRFileDesc** aNSPRFileDesc);
+
   protected:
     typedef nsClassHashtable<nsCStringHashKey, nsJARManifestItem> ManifestDataHashtable;
 
     //-- Private data members
     nsCOMPtr<nsIFile>        mZipFile;        // The zip/jar file on disk
     nsCString                mOuterZipEntry;  // The entry in the zip this zip is reading from
     nsRefPtr<nsZipArchive>   mZip;            // The underlying zip archive
     ManifestDataHashtable    mManifestData;   // Stores metadata for each entry
@@ -190,25 +192,30 @@ public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIZIPREADERCACHE
   NS_DECL_NSIOBSERVER
 
   nsZipReaderCache();
 
   nsresult ReleaseZip(nsJAR* reader);
 
+  bool IsMustCacheFdEnabled() {
+    return mMustCacheFd;
+  }
+
   typedef nsRefPtrHashtable<nsCStringHashKey, nsJAR> ZipsHashtable;
 
 protected:
 
   virtual ~nsZipReaderCache();
 
   mozilla::Mutex        mLock;
   uint32_t              mCacheSize;
   ZipsHashtable         mZips;
+  bool                  mMustCacheFd;
 
 #ifdef ZIP_CACHE_HIT_RATE
   uint32_t              mZipCacheLookups;
   uint32_t              mZipCacheHits;
   uint32_t              mZipCacheFlushes;
   uint32_t              mZipSyncMisses;
 #endif
 
--- a/modules/libjar/nsJARChannel.cpp
+++ b/modules/libjar/nsJARChannel.cpp
@@ -17,16 +17,17 @@
 
 #include "nsIScriptSecurityManager.h"
 #include "nsIPrincipal.h"
 #include "nsIFileURL.h"
 
 #include "mozilla/Preferences.h"
 #include "mozilla/net/RemoteOpenFileChild.h"
 #include "nsITabChild.h"
+#include "private/pprio.h"
 
 using namespace mozilla;
 using namespace mozilla::net;
 
 static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID);
 
 // the entry for a directory will either be empty (in the case of the
 // top-level directory) or will end with a slash
@@ -352,36 +353,61 @@ nsJARChannel::LookupFile()
         rv = mJarBaseURI->GetScheme(scheme);
         if (NS_SUCCEEDED(rv) && scheme.EqualsLiteral("remoteopenfile")) {
             nsRefPtr<RemoteOpenFileChild> remoteFile = new RemoteOpenFileChild();
             rv = remoteFile->Init(mJarBaseURI, mAppURI);
             NS_ENSURE_SUCCESS(rv, rv);
             mJarFile = remoteFile;
 
             nsIZipReaderCache *jarCache = gJarHandler->JarCache();
-            if (jarCache && !mEnsureChildFd) {
+            if (jarCache) {
                 bool cached = false;
                 rv = jarCache->IsCached(mJarFile, &cached);
                 if (NS_SUCCEEDED(rv) && cached) {
                     // zipcache already has file mmapped: don't open on parent,
-                    // just return and proceed to cache hit in CreateJarInput()
+                    // just return and proceed to cache hit in CreateJarInput().
+                    // When the file descriptor is needed, get it from JAR cache
+                    // if available, otherwise do the remote open to get a new
+                    // one.
+                    #if defined(XP_WIN) || defined(MOZ_WIDGET_COCOA)
+                    // Windows/OSX desktop builds skip remoting, we don't need
+                    // file descriptor here.
                     return NS_OK;
+                    #else
+                    if (!mEnsureChildFd) {
+                        return NS_OK;
+                    }
+                    PRFileDesc *fd = nullptr;
+                    jarCache->GetFd(mJarFile, &fd);
+                    if (fd) {
+                        PROsfd osfd = dup(PR_FileDesc2NativeHandle(fd));
+                        if (osfd == -1) {
+                            return NS_ERROR_FAILURE;
+                        }
+                        remoteFile->SetNSPRFileDesc(PR_ImportFile(osfd));
+                        return NS_OK;
+                    }
+                    #endif
                 }
             }
 
             mOpeningRemote = true;
 
             if (gJarHandler->RemoteOpenFileInProgress(remoteFile, this) &&
                 !mEnsureChildFd) {
                 // JarHandler will trigger OnRemoteFileOpen() after the first
                 // request for this file completes and we'll get a JAR cache
                 // hit.
                 return NS_OK;
             }
 
+            if (mEnsureChildFd && jarCache) {
+                jarCache->SetMustCacheFd(remoteFile, true);
+            }
+
             // Open file on parent: OnRemoteFileOpenComplete called when done
             nsCOMPtr<nsITabChild> tabChild;
             NS_QueryNotificationCallbacks(this, tabChild);
             nsCOMPtr<nsILoadContext> loadContext;
             NS_QueryNotificationCallbacks(this, loadContext);
             rv = remoteFile->AsyncRemoteFileOpen(PR_RDONLY, this, tabChild,
                                                  loadContext);
             NS_ENSURE_SUCCESS(rv, rv);
@@ -1039,17 +1065,21 @@ nsJARChannel::OnStopRequest(nsIRequest *
     mPump = 0;
     mIsPending = false;
     mDownloader = 0; // this may delete the underlying jar file
 
     // Drop notification callbacks to prevent cycles.
     mCallbacks = 0;
     mProgressSink = 0;
 
-    if (mOpeningRemote) {
+    if (mEnsureChildFd) {
+      nsIZipReaderCache *jarCache = gJarHandler->JarCache();
+      if (jarCache) {
+          jarCache->SetMustCacheFd(mJarFile, false);
+      }
       // To deallocate file descriptor by RemoteOpenFileChild destructor.
       mJarFile = nullptr;
     }
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
--- a/modules/libjar/nsZipArchive.cpp
+++ b/modules/libjar/nsZipArchive.cpp
@@ -166,17 +166,18 @@ nsZipHandle::nsZipHandle()
   , mRefCnt(0)
 {
   MOZ_COUNT_CTOR(nsZipHandle);
 }
 
 NS_IMPL_ADDREF(nsZipHandle)
 NS_IMPL_RELEASE(nsZipHandle)
 
-nsresult nsZipHandle::Init(nsIFile *file, nsZipHandle **ret, PRFileDesc **aFd)
+nsresult nsZipHandle::Init(nsIFile *file, bool aMustCacheFd, nsZipHandle **ret,
+                           PRFileDesc **aFd)
 {
   mozilla::AutoFDClose fd;
   int32_t flags = PR_RDONLY;
 #if defined(XP_WIN)
   flags |= nsIFile::OS_READAHEAD;
 #endif
   nsresult rv = file->OpenNSPRFileDesc(flags, 0000, &fd.rwget());
   if (NS_FAILED(rv))
@@ -203,16 +204,20 @@ nsresult nsZipHandle::Init(nsIFile *file
     PR_CloseFileMap(map);
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
 #if defined(XP_WIN)
   if (aFd) {
     *aFd = fd.forget();
   }
+#else
+  if (aMustCacheFd) {
+    handle->mNSPRFileDesc = fd.forget();
+  }
 #endif
   handle->mMap = map;
   handle->mFile.Init(file);
   handle->mLen = (uint32_t) size;
   handle->mFileData = buf;
   handle.forget(ret);
   return NS_OK;
 }
@@ -239,16 +244,26 @@ nsresult nsZipHandle::Init(nsZipArchive 
   return NS_OK;
 }
 
 int64_t nsZipHandle::SizeOfMapping()
 {
     return mLen;
 }
 
+nsresult nsZipHandle::GetNSPRFileDesc(PRFileDesc** aNSPRFileDesc)
+{
+  if (!aNSPRFileDesc) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+
+  *aNSPRFileDesc = mNSPRFileDesc;
+  return NS_OK;
+}
+
 nsZipHandle::~nsZipHandle()
 {
   if (mMap) {
     PR_MemUnmap((void *)mFileData, mLen);
     PR_CloseFileMap(mMap);
   }
   mFileData = nullptr;
   mMap = nullptr;
@@ -274,24 +289,25 @@ nsresult nsZipArchive::OpenArchive(nsZip
   nsresult rv = BuildFileList(aFd);
   if (NS_SUCCEEDED(rv)) {
     if (aZipHandle->mFile)
       aZipHandle->mFile.GetURIString(mURI);
   }
   return rv;
 }
 
-nsresult nsZipArchive::OpenArchive(nsIFile *aFile)
+nsresult nsZipArchive::OpenArchive(nsIFile *aFile, bool aMustCacheFd)
 {
   nsRefPtr<nsZipHandle> handle;
 #if defined(XP_WIN)
   mozilla::AutoFDClose fd;
-  nsresult rv = nsZipHandle::Init(aFile, getter_AddRefs(handle), &fd.rwget());
+  nsresult rv = nsZipHandle::Init(aFile, aMustCacheFd, getter_AddRefs(handle),
+                                  &fd.rwget());
 #else
-  nsresult rv = nsZipHandle::Init(aFile, getter_AddRefs(handle));
+  nsresult rv = nsZipHandle::Init(aFile, aMustCacheFd, getter_AddRefs(handle));
 #endif
   if (NS_FAILED(rv))
     return rv;
 
 #if defined(XP_WIN)
   return OpenArchive(handle, fd.get());
 #else
   return OpenArchive(handle);
--- a/modules/libjar/nsZipArchive.h
+++ b/modules/libjar/nsZipArchive.h
@@ -115,20 +115,21 @@ public:
    */
   nsresult OpenArchive(nsZipHandle *aZipHandle, PRFileDesc *aFd = nullptr);
 
   /** 
    * OpenArchive 
    * 
    * Convenience function that generates nsZipHandle
    *
-   * @param   aFile  The file used to access the zip
+   * @param   aFile         The file used to access the zip
+   * @param   aMustCacheFd  Optional flag to keep the PRFileDesc in nsZipHandle
    * @return  status code
    */
-  nsresult OpenArchive(nsIFile *aFile);
+  nsresult OpenArchive(nsIFile *aFile, bool aMustCacheFd = false);
 
   /**
    * Test the integrity of items in this archive by running
    * a CRC check after extracting each item into a memory 
    * buffer.  If an entry name is supplied only the 
    * specified item is tested.  Else, if null is supplied
    * then all the items in the archive are tested.
    *
@@ -375,36 +376,39 @@ public:
     return ret;
   }
 };
 
 class nsZipHandle {
 friend class nsZipArchive;
 friend class mozilla::FileLocation;
 public:
-  static nsresult Init(nsIFile *file, nsZipHandle **ret,
+  static nsresult Init(nsIFile *file, bool aMustCacheFd, nsZipHandle **ret,
                        PRFileDesc **aFd = nullptr);
   static nsresult Init(nsZipArchive *zip, const char *entry,
                        nsZipHandle **ret);
 
   NS_METHOD_(MozExternalRefCountType) AddRef(void);
   NS_METHOD_(MozExternalRefCountType) Release(void);
 
   int64_t SizeOfMapping();
 
+  nsresult GetNSPRFileDesc(PRFileDesc** aNSPRFileDesc);
+
 protected:
   const uint8_t * mFileData; /* pointer to mmaped file */
   uint32_t        mLen;      /* length of file and memory mapped area */
   mozilla::FileLocation mFile; /* source file if any, for logging */
 
 private:
   nsZipHandle();
   ~nsZipHandle();
 
   PRFileMap *                       mMap;    /* nspr datastructure for mmap */
+  mozilla::AutoFDClose              mNSPRFileDesc;
   nsAutoPtr<nsZipItemPtr<uint8_t> > mBuf;
   mozilla::ThreadSafeAutoRefCnt     mRefCnt; /* ref count */
   NS_DECL_OWNINGTHREAD
 };
 
 nsresult gZlibInit(z_stream *zs);
 
 #endif /* nsZipArchive_h_ */
--- a/netwerk/ipc/RemoteOpenFileChild.cpp
+++ b/netwerk/ipc/RemoteOpenFileChild.cpp
@@ -244,16 +244,28 @@ RemoteOpenFileChild::AsyncRemoteFileOpen
   AddIPDLReference();
 
   mListener = aListener;
   mAsyncOpenCalled = true;
   return NS_OK;
 #endif
 }
 
+nsresult
+RemoteOpenFileChild::SetNSPRFileDesc(PRFileDesc* aNSPRFileDesc)
+{
+  MOZ_ASSERT(!mNSPRFileDesc);
+  if (mNSPRFileDesc) {
+    return NS_ERROR_ALREADY_OPENED;
+  }
+
+  mNSPRFileDesc = aNSPRFileDesc;
+  return NS_OK;
+}
+
 void
 RemoteOpenFileChild::OnCachedFileDescriptor(const nsAString& aPath,
                                             const FileDescriptor& aFD)
 {
 #ifdef DEBUG
   if (!aPath.IsEmpty()) {
     MOZ_ASSERT(mFile);
 
--- a/netwerk/ipc/RemoteOpenFileChild.h
+++ b/netwerk/ipc/RemoteOpenFileChild.h
@@ -72,16 +72,18 @@ public:
   // Send message to parent to tell it to open file handle for file.
   // TabChild is required, for IPC security.
   // Note: currently only PR_RDONLY is supported for 'flags'
   nsresult AsyncRemoteFileOpen(int32_t aFlags,
                                nsIRemoteOpenFileListener* aListener,
                                nsITabChild* aTabChild,
                                nsILoadContext *aLoadContext);
 
+  nsresult SetNSPRFileDesc(PRFileDesc* aNSPRFileDesc);
+
   void ReleaseIPDLReference()
   {
     Release();
   }
 
 private:
   RemoteOpenFileChild(const RemoteOpenFileChild& other);