Closed Bug 1229589 Opened 9 years ago Closed 8 years ago

Make TCPSocket more efficient about removing stale input streams

Categories

(Core :: DOM: Core & HTML, defect)

defect
Not set
normal

Tracking

()

RESOLVED FIXED
mozilla49
Tracking Status
firefox45 --- affected
firefox49 --- fixed

People

(Reporter: jdm, Assigned: wizard_A, Mentored)

Details

(Whiteboard: [lang=c++])

Attachments

(2 files, 6 obsolete files)

TCPSocket::NotifyCopyComplete only removes the first stream from the multiplex stream, even though we could have copied more than one. If that's the case, it notices that the queue is non-empty and attempts to copy them again. This is wasteful, and makes it harder to reason about the correctness of this code.

I propose we add an `nsTArray<nsCOMPtr<nsIInputStream>>` in `TCPSocket` for storing any data passed to Send while mAsyncCopierActive is true. In NotifyCopyComplete, we can remove all the streams from the multiplex stream, then append the items from the new array member, and everything should continue to Just Work.

We can ensure that it's working by running the tests:
./mach mochitest dom/network/tests/test_client_and_server_basics.html
./mach mochitest-e10s dom/network/tests/test_client_and_server_basics.html

Code: dom/network/TCPSocket.cpp
Hi, I would like to work on this bug. Can you assign it to me please.
Hi Salah! We tend to assign bugs to new contributors after the first patch is submitted. Here are the steps I expect for solving this bug:

* in dom/network/TCPSocket.h, we add a new member as described in the original comment.
* in dom/network/TCPSocket.cpp in TCPSocket::Send(nsIInputStream* aStream, uint32_t aByteLength), before appending to the multiplex stream we first check if mAsyncCopierActive is true. If so, we append to the new member instead.
* in TCPSocket::NotifyCopyComplete, instead of only removing the stream in position 0, we will want to continuously remove the first stream while the multiplex stream is not empty. After that, we should append all of the streams in the new member added in the first step, and clear out that new member (see the nsTArray API at https://dxr.mozilla.org/mozilla-central/source/xpcom/glue/nsTArray.h?from=nstarray#2084 )

Does that make sense?
Okay here is what I have done. 


* in dom/network/TCPSocket.h, we add a new member as described in the original comment.


// Input stream machinery
  nsCOMPtr<nsIInputStreamPump> mInputStreamPump;
  nsCOMPtr<nsIScriptableInputStream> mInputStreamScriptable;
  nsCOMPtr<nsIBinaryInputStream> mInputStreamBinary;
++ nsTArray<nsCOMPtr<nsIInputStream>>


I have added the new member in the input stream as it is storing data passed to it. Im not sure if this is the correct place or if it needs to be defined as public first at the top.


in dom/network/TCPSocket.cpp in TCPSocket::Send(nsIInputStream* aStream, uint32_t aByteLength), before appending to the multiplex stream we first check if mAsyncCopierActive is true. If so, we append to the new member instead.


bool
TCPSocket::Send(nsIInputStream* aStream, uint32_t aByteLength)
{
  uint64_t newBufferedAmount = BufferedAmount() + aByteLength;
  bool bufferFull = newBufferedAmount > BUFFER_SIZE;
  if (bufferFull) {
    // If we buffered more than some arbitrary amount of data,
    // (65535 right now) we should tell the caller so they can
    // wait until ondrain is called if they so desire. Once all the
    // buffered data has been written to the socket, ondrain is
    // called.
    mWaitingForDrain = true;
  }

  if (mSocketBridgeChild) {
    // In the child, we just add the buffer length to our bufferedAmount and let
    // the parent update our bufferedAmount when the data have been sent.
    mBufferedAmount = newBufferedAmount;
    return !bufferFull;
  }

++if (mAsyncCopierActive == true) {
++    ???
++}



  if (mWaitingForStartTLS) {
    // When we are waiting for starttls, newStream is added to pendingData
    // and will be appended to multiplexStream after tls had been set up.
    mPendingDataAfterStartTLS.AppendElement(aStream);
  } else {
    mMultiplexStream->AppendStream(aStream);
  }

  EnsureCopying();



I have added the If statement to check if it is true. However I’m not sure how exactly I should append to the new member.

Appreciate any feedback.
Attached patch bug1229589.patchSplinter Review
Hi Josh,

I have attached a patch for this bug, could you please provide some feedback.

Kind regards,
Seema Shad
Attachment #8697028 - Flags: feedback?(josh)
Comment on attachment 8697028 [details] [diff] [review]
bug1229589.patch

Review of attachment 8697028 [details] [diff] [review]:
-----------------------------------------------------------------

Hi Seema! I apologize for being silent for so long - your messages came during a week-long conference, then there were the holidays, etc. This is a good start, and I've included some comments that should hopefully clarify the missing pieces. Let me know if anything else is unclear!

::: dom/network/TCPSocket.cpp
@@ +398,5 @@
>  TCPSocket::NotifyCopyComplete(nsresult aStatus)
>  {
>    mAsyncCopierActive = false;
> +
> +  while (mMultiplexStream->NotEmpty()) {

You'll want to use the methods from https://dxr.mozilla.org/mozilla-central/source/obj-x86_64-unknown-linux-gnu/dist/include/nsIMultiplexInputStream.h?from=nsimultiplexinputstream#25 . There should be no need to include a counter here, though; we want to remove the 0th element until no elements remain.

@@ +404,5 @@
> +    mMultiplexStream->NotEmpty(i);
> +    i++;
> +  }
> +
> +  mPassedDataToSend->AppendElements;

This will need to be a loop that removes the 0th element from mPassedDataToSend and appends it to mMultiplexStream.

@@ +405,5 @@
> +    i++;
> +  }
> +
> +  mPassedDataToSend->AppendElements;
> +       

nit: trailing whitespace

@@ +891,5 @@
>      // and will be appended to multiplexStream after tls had been set up.
>      mPendingDataAfterStartTLS.AppendElement(aStream);
>    } else {
> +    if {mAsynCopierActive == true) {
> +      mPassedDataToSend->AppendStream(aStream);

nsTArray doesn't have an AppendStream; you'll want AppendElement instead (https://dxr.mozilla.org/mozilla-central/source/xpcom/glue/nsTArray.h#1593)

::: dom/network/TCPSocket.h
@@ +234,5 @@
>    bool mWaitingForStartTLS;
>    // The buffered data awaiting the TLS upgrade to finish.
>    nsTArray<nsCOMPtr<nsIInputStream>> mPendingDataAfterStartTLS;
> +  //Stores passed data to send while mAsyncCopierActive is true
> +  nsTArray<nsCOMPTr<nsIInputStream>>mPassedDataToSend;

nit: add a space after the >> here. A clearer name could be `mPendingDataWhileCopierActive`.

@@ +235,5 @@
>    // The buffered data awaiting the TLS upgrade to finish.
>    nsTArray<nsCOMPtr<nsIInputStream>> mPendingDataAfterStartTLS;
> +  //Stores passed data to send while mAsyncCopierActive is true
> +  nsTArray<nsCOMPTr<nsIInputStream>>mPassedDataToSend;
> +  

nit: trailing whitespace
Attachment #8697028 - Flags: feedback?(josh) → feedback+
Hi Josh,

I have started working on this...

Thanks,
Amit.
Hi Josh,

Here is what i have implemented so far.. plz tell me if i am headed the right direction....

Thanks,
Amit.
Attachment #8740618 - Flags: feedback?(josh)
Attachment #8740618 - Attachment is patch: true
Comment on attachment 8740618 [details] [diff] [review]
Bug-1229589_Implement_efficient_TCPSocket.patch

That's the right idea, but as you noticed we should be appending to the new array instead of mMultiplexStream in the new `else if` case that's been added.
Attachment #8740618 - Flags: feedback?(josh) → feedback+
Hi Josh,

I have made the changes and the tests mentioned are passing. Requesting you to kindly review the changes made.

Thanking You,
Amit.
Attachment #8740618 - Attachment is obsolete: true
Attachment #8741135 - Flags: review?(josh)
Comment on attachment 8741135 [details] [diff] [review]
Bug-1229589_Implement_efficient_TCPSocket.patch

Review of attachment 8741135 [details] [diff] [review]:
-----------------------------------------------------------------

Good start! Sorry for the delay in reviewing the changes.

::: dom/network/TCPSocket.cpp
@@ +411,5 @@
> +  uint32_t countRemaining;
> +  nsresult rvRemaining = mMultiplexStream->GetCount(&countRemaining);
> +  NS_ENSURE_SUCCESS_VOID(rvRemaining);
> +
> +  do {

Let's just do a `while (countRemaining--) {` loop instead of calling GetCount each time.

@@ +915,5 @@
>      // and will be appended to multiplexStream after tls had been set up.
>      mPendingDataAfterStartTLS.AppendElement(aStream);
> +  } else if (mAsyncCopierActive) {
> +    // While the AsyncCopier is still active..
> +    mPendingDataWhileCopierActive.AppendElement(aStream);

We need to actually transfer the streams from mPendingDataWhileCopierActive to mMultiplexStream when the copier is no longer active in NotifyCopyComplete.
Attachment #8741135 - Flags: review?(josh) → feedback+
Assignee: nobody → amitforfriends_dns
Hi Josh,

Thank you for the review comments. I have worked on them and the patch is attached.
Please check if the changes made would resolve the bug.

Thanks,
Amit.
Attachment #8741135 - Attachment is obsolete: true
Attachment #8743483 - Flags: feedback?(josh)
Comment on attachment 8743483 [details] [diff] [review]
Bug-1229589_Implement_efficient_TCPSocket.patch

Review of attachment 8743483 [details] [diff] [review]:
-----------------------------------------------------------------

Looks good, thank you! You should apply for access to our tryserver so we can go through the process of getting this merged: https://wiki.mozilla.org/ReleaseEngineering/TryServer#Getting_access_to_the_Try_Server

::: dom/network/TCPSocket.cpp
@@ +415,5 @@
> +  while (countRemaining--) {
> +    mMultiplexStream->RemoveStream(0);
> +  }
> +
> +  if (!mAsyncCopierActive) {

No need for this check; we set it to false earlier.
Attachment #8743483 - Flags: feedback?(josh) → review+
Hi Josh,

Thank you very much for your comments. I did that change there since I was not very sure of what you meant in your last line in comment in comment 10. Please guide me as to whether i need to change the above code or let it be...

Moreover, I would require someone to vouch for me to get an access to the try-server. Since, this is my third bug, i was not very sure as to my eligibility for the same. Will you vouch for me, only if you feel appropriate??

Thanks a lot,
Amit.
The first line of NotifyCopyComplete is `mAsyncCopierActive = false;`, so the if check is not useful :) Please go ahead and remove. Also, I will be happy to vouch for you.
Thanks a lot Josh for vouching for me.. I'll file the bug after this bug is resolved. Thanks.. :)
Attachment #8743483 - Attachment is obsolete: true
Attachment #8746531 - Flags: review?(josh)
Comment on attachment 8746531 [details] [diff] [review]
Bug-1229589_Implement_efficient_TCPSocket.patch

Review of attachment 8746531 [details] [diff] [review]:
-----------------------------------------------------------------

::: dom/network/TCPSocket.cpp
@@ +914,5 @@
>      // and will be appended to multiplexStream after tls had been set up.
>      mPendingDataAfterStartTLS.AppendElement(aStream);
> +  } else if (mAsyncCopierActive) {
> +    // While the AsyncCopier is still active..
> +    mPendingDataWhileCopierActive.AppendElement(aStream);

This patch is missing the code that transfer the elements of mPendingDataWhileCopierActive in NotifyCopyComplete...
Attachment #8746531 - Flags: review?(josh) → review-
I hope i did not mess up this time... Thanks... :)
Attachment #8746531 - Attachment is obsolete: true
Attachment #8749228 - Flags: review?(josh)
Comment on attachment 8749228 [details] [diff] [review]
Bug-1229589_Implement_efficient_TCPSocket.patch

Review of attachment 8749228 [details] [diff] [review]:
-----------------------------------------------------------------

::: dom/network/TCPSocket.cpp
@@ +415,5 @@
> +  while (countRemaining--) {
> +    mMultiplexStream->RemoveStream(0);
> +  }
> +
> +  if (!mAsyncCopierActive) {

This is what I commented about last time: this check for !mAsyncCopierActive is redundant - it is always true because we set mAsyncCopierActive to false earlier in this method.
Attachment #8749228 - Flags: review?(josh)
Appologies... My bad... So i will go ahead and remove the if condition. And, the rest of the code (while loop) stays the same or is there any other implementation of copying mPendingDataWhileCopierActive to mMultiplexStream??
Yes, the rest of the code looks fine to me. Apologies for the delay; I was at a conference last week, and then it was a holiday weekend.
Thanks Josh. Requesting your review...
Attachment #8749228 - Attachment is obsolete: true
Attachment #8755887 - Flags: review?(josh)
Comment on attachment 8755887 [details] [diff] [review]
Bug-1229589_Implement_efficient_TCPSocket.patch

Review of attachment 8755887 [details] [diff] [review]:
-----------------------------------------------------------------

::: dom/network/TCPSocket.cpp
@@ +415,5 @@
> +  while (countRemaining--) {
> +    mMultiplexStream->RemoveStream(0);
> +  }
> +
> +  if (!mAsyncCopierActive) {

This if check is still here. Was this a mistake, or were the previous comments unclear?
Attachment #8755887 - Flags: review?(josh) → review-
HI Josh... Really very sorry for this.. probably some mistake somewhere.. Hence, this time i am attaching the text of the patch.. Sorry for the mess..
Attachment #8755887 - Attachment is obsolete: true
Attachment #8756074 - Flags: review?(josh)
Attachment #8756074 - Flags: review?(josh) → review+
I've pushed this patch to our automated testing server. If there are no test failures related to this change, we can merge it!
Thanks a ton Josh. I hope to do better in my next bug fix.
The failures in on the test machines are all known Windows 7 problems that are unrelated to these changes, so this is good to go.
Keywords: checkin-needed
Just as an fyi for the future, I had to edit the commit message to remove the ":" because the commit hook rejects "Bug: XXX", but accepts "Bug XXX".
https://hg.mozilla.org/mozilla-central/rev/a4d93c6954d1
Status: NEW → RESOLVED
Closed: 8 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla49
Component: DOM → DOM: Core & HTML
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: