Bug 1100398 P3 Make nsStorageStream's input streams cloneable. r=froydnj
authorBen Kelly <ben@wanderview.com>
Tue, 10 Feb 2015 23:55:43 -0500
changeset 228746 db0d65c0b7a7cecdeb2b8612729f19d03f49dffd
parent 228745 507718807f6d78af80a493ecbdef21fcd5108631
child 228747 ef97268b8d6a5b55bb3965fe4f96a3b5b995855a
push id28271
push usercbook@mozilla.com
push dateThu, 12 Feb 2015 14:33:39 +0000
treeherdermozilla-central@81f979b17fbd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj
bugs1100398
milestone38.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1100398 P3 Make nsStorageStream's input streams cloneable. r=froydnj
xpcom/io/nsStorageStream.cpp
xpcom/tests/gtest/TestStorageStream.cpp
--- a/xpcom/io/nsStorageStream.cpp
+++ b/xpcom/io/nsStorageStream.cpp
@@ -12,16 +12,17 @@
  * with the attendant performance loss and heap fragmentation.
  */
 
 #include "nsAlgorithm.h"
 #include "nsStorageStream.h"
 #include "nsSegmentedBuffer.h"
 #include "nsStreamUtils.h"
 #include "nsCOMPtr.h"
+#include "nsICloneableInputStream.h"
 #include "nsIInputStream.h"
 #include "nsIIPCSerializableInputStream.h"
 #include "nsISeekableStream.h"
 #include "prlog.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Likely.h"
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/ipc/InputStreamUtils.h"
@@ -340,31 +341,33 @@ nsStorageStream::Seek(int32_t aPosition)
 
 ////////////////////////////////////////////////////////////////////////////////
 
 // There can be many nsStorageInputStreams for a single nsStorageStream
 class nsStorageInputStream MOZ_FINAL
   : public nsIInputStream
   , public nsISeekableStream
   , public nsIIPCSerializableInputStream
+  , public nsICloneableInputStream
 {
 public:
   nsStorageInputStream(nsStorageStream* aStorageStream, uint32_t aSegmentSize)
     : mStorageStream(aStorageStream), mReadCursor(0),
       mSegmentEnd(0), mSegmentNum(0),
       mSegmentSize(aSegmentSize), mLogicalCursor(0),
       mStatus(NS_OK)
   {
     NS_ADDREF(mStorageStream);
   }
 
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIINPUTSTREAM
   NS_DECL_NSISEEKABLESTREAM
   NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM
+  NS_DECL_NSICLONEABLEINPUTSTREAM
 
 private:
   ~nsStorageInputStream()
   {
     NS_IF_RELEASE(mStorageStream);
   }
 
 protected:
@@ -389,17 +392,18 @@ private:
   {
     return aPosition & (mSegmentSize - 1);
   }
 };
 
 NS_IMPL_ISUPPORTS(nsStorageInputStream,
                   nsIInputStream,
                   nsISeekableStream,
-                  nsIIPCSerializableInputStream)
+                  nsIIPCSerializableInputStream,
+                  nsICloneableInputStream)
 
 NS_IMETHODIMP
 nsStorageStream::NewInputStream(int32_t aStartingOffset,
                                 nsIInputStream** aInputStream)
 {
   if (NS_WARN_IF(!mSegmentedBuffer)) {
     return NS_ERROR_NOT_INITIALIZED;
   }
@@ -611,16 +615,29 @@ nsStorageInputStream::Serialize(InputStr
 bool
 nsStorageInputStream::Deserialize(const InputStreamParams& aParams,
                                   const FileDescriptorArray&)
 {
   NS_NOTREACHED("We should never attempt to deserialize a storage input stream.");
   return false;
 }
 
+NS_IMETHODIMP
+nsStorageInputStream::GetCloneable(bool* aCloneableOut)
+{
+  *aCloneableOut = true;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsStorageInputStream::Clone(nsIInputStream** aCloneOut)
+{
+  return mStorageStream->NewInputStream(mLogicalCursor, aCloneOut);
+}
+
 nsresult
 NS_NewStorageStream(uint32_t aSegmentSize, uint32_t aMaxSize,
                     nsIStorageStream** aResult)
 {
   nsStorageStream* storageStream = new nsStorageStream();
   if (!storageStream) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
--- a/xpcom/tests/gtest/TestStorageStream.cpp
+++ b/xpcom/tests/gtest/TestStorageStream.cpp
@@ -1,92 +1,89 @@
 /* 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 <stdlib.h>
-#include "nsIStorageStream.h"
+#include "gtest/gtest.h"
+#include "Helpers.h"
+#include "nsCOMPtr.h"
+#include "nsICloneableInputStream.h"
 #include "nsIInputStream.h"
 #include "nsIOutputStream.h"
-#include "nsCOMPtr.h"
-#include "gtest/gtest.h"
+#include "nsIStorageStream.h"
 
-TEST(TestStorageStreams, Main)
+namespace {
+void
+WriteData(nsIOutputStream* aOut, nsTArray<char>& aData, uint32_t aNumBytes,
+          nsACString& aDataWritten)
 {
-  char kData[4096];
-  memset(kData, 0, sizeof(kData));
+  uint32_t n;
+  nsresult rv = aOut->Write(aData.Elements(), aNumBytes, &n);
+  EXPECT_TRUE(NS_SUCCEEDED(rv));
+  aDataWritten.Append(aData.Elements(), aNumBytes);
+}
+
+} // anonymous namespace
+TEST(StorageStreams, Main)
+{
+  // generate some test data we will write in 4k chunks to the stream
+  nsTArray<char> kData;
+  testing::CreateData(4096, kData);
+
+  // track how much data was written so we can compare at the end
+  nsAutoCString dataWritten;
 
   nsresult rv;
   nsCOMPtr<nsIStorageStream> stor;
 
-  rv = NS_NewStorageStream(4096, UINT32_MAX, getter_AddRefs(stor));
+  rv = NS_NewStorageStream(kData.Length(), UINT32_MAX, getter_AddRefs(stor));
   EXPECT_TRUE(NS_SUCCEEDED(rv));
 
   nsCOMPtr<nsIOutputStream> out;
   rv = stor->GetOutputStream(0, getter_AddRefs(out));
   EXPECT_TRUE(NS_SUCCEEDED(rv));
 
-  uint32_t n;
-
-  rv = out->Write(kData, sizeof(kData), &n);
-  EXPECT_TRUE(NS_SUCCEEDED(rv));
-
-  rv = out->Write(kData, sizeof(kData), &n);
-  EXPECT_TRUE(NS_SUCCEEDED(rv));
+  WriteData(out, kData, kData.Length(), dataWritten);
+  WriteData(out, kData, kData.Length(), dataWritten);
 
   rv = out->Close();
   EXPECT_TRUE(NS_SUCCEEDED(rv));
-
   out = nullptr;
 
   nsCOMPtr<nsIInputStream> in;
   rv = stor->NewInputStream(0, getter_AddRefs(in));
   EXPECT_TRUE(NS_SUCCEEDED(rv));
 
-  char buf[4096];
+  nsCOMPtr<nsICloneableInputStream> cloneable = do_QueryInterface(in);
+  ASSERT_TRUE(cloneable != nullptr);
+  ASSERT_TRUE(cloneable->GetCloneable());
 
-  // consume contents of input stream
-  do {
-    rv = in->Read(buf, sizeof(buf), &n);
-    EXPECT_TRUE(NS_SUCCEEDED(rv));
-  } while (n != 0);
+  nsCOMPtr<nsIInputStream> clone;
+  rv = cloneable->Clone(getter_AddRefs(clone));
 
-  rv = in->Close();
-  EXPECT_TRUE(NS_SUCCEEDED(rv));
+  testing::ConsumeAndValidateStream(in, dataWritten);
+  testing::ConsumeAndValidateStream(clone, dataWritten);
   in = nullptr;
+  clone = nullptr;
 
   // now, write 3 more full 4k segments + 11 bytes, starting at 8192
   // total written equals 20491 bytes
 
-  rv = stor->GetOutputStream(8192, getter_AddRefs(out));
-  EXPECT_TRUE(NS_SUCCEEDED(rv));
-
-  rv = out->Write(kData, sizeof(kData), &n);
+  rv = stor->GetOutputStream(dataWritten.Length(), getter_AddRefs(out));
   EXPECT_TRUE(NS_SUCCEEDED(rv));
 
-  rv = out->Write(kData, sizeof(kData), &n);
-  EXPECT_TRUE(NS_SUCCEEDED(rv));
-
-  rv = out->Write(kData, sizeof(kData), &n);
-  EXPECT_TRUE(NS_SUCCEEDED(rv));
-
-  rv = out->Write(kData, 11, &n);
-  EXPECT_TRUE(NS_SUCCEEDED(rv));
+  WriteData(out, kData, kData.Length(), dataWritten);
+  WriteData(out, kData, kData.Length(), dataWritten);
+  WriteData(out, kData, kData.Length(), dataWritten);
+  WriteData(out, kData, 11, dataWritten);
 
   rv = out->Close();
   EXPECT_TRUE(NS_SUCCEEDED(rv));
-
   out = nullptr;
 
   // now, read all
   rv = stor->NewInputStream(0, getter_AddRefs(in));
   EXPECT_TRUE(NS_SUCCEEDED(rv));
 
-  // consume contents of input stream
-  do {
-    rv = in->Read(buf, sizeof(buf), &n);
-    EXPECT_TRUE(NS_SUCCEEDED(rv));
-  } while (n != 0);
-
-  rv = in->Close();
-  EXPECT_TRUE(NS_SUCCEEDED(rv));
+  testing::ConsumeAndValidateStream(in, dataWritten);
   in = nullptr;
 }