-
Notifications
You must be signed in to change notification settings - Fork 548
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Rewrite sslproto.py #176
Rewrite sslproto.py #176
Conversation
The failing test is unstable,
According to libuv docs, the following uvloop/uvloop/handles/stream.pyx Lines 935 to 980 in b996e0f
However, this code didn't handle |
Ah, that makes sense. Thanks for fixing that; can you make a fix in a separate PR? What's the projected timeline for this PR? I assume you are planning to add more SSL tests, right? Or is it ready for a review now? |
Oh sure thing, will do.
Yes, I was planning to add more tests (renegotiation for example), and fix some obvious issues and make improvements during the testing. Let's do the review tomorrow anyway, shall we? 😃 |
Anytime this week works. |
663268f
to
c178c6b
Compare
01be886
to
321ab23
Compare
tests/test_tcp.py
Outdated
@@ -9,6 +9,7 @@ | |||
import threading | |||
import weakref | |||
|
|||
from OpenSSL import SSL |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe from OpenSSL import SSL as open_ssl
? :) To make it obvious where OpenSSL is really used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure
tests/test_tcp.py
Outdated
# hack reader and writer to call start_tls() | ||
transport = writer._transport | ||
writer._transport = None | ||
reader._transport = None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wow, you're brave! :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LOL was rushing to avoid manual protocol code - perhaps it's better be replaced by protocol so that the test can be robust enough even if asyncio changes its implementation in the future.
uvloop/sslproto.pyx
Outdated
break | ||
elif self._state == _SHUTDOWN: | ||
self._do_read() | ||
self._do_shutdown() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_do_read()
should be removed in _SHUTDOWN
, because a peer should start to discard incoming app data once it sends the close_notify
alert.
In short: I like the new code, it's easy to follow. Great job! Don't have any major comments. The state transitions seem fine, the overall logic is OK too. I'd continue iterating on the codebase and adding tests (your current ToDo is great too!) At some point when we think it's ready we'll commit the Python implementation (to have it in the repo) and start to Cythonize it to make it slightly faster. The pure-Python implementation will go straight to asyncio 3.8. |
eb7387d
to
ff4e5d8
Compare
I'm adding a new state
Usually APP data will transiently stay in While in
|
(Took 1.5 hours to correctly write a FLUSHING test first, but only half an hour to actually implement the FLUSHING state 😃) |
Working on A question here - do we want to treat peer's Update: it is now implemented as follows: treating TLS as transport details, |
b757099
to
5b06936
Compare
Spent some time to make it run faster in uvloop - about 20% ~ 40% faster than original uvloop in 1~100 KiB echo benchmark. Here're the cProfiled diagrams for time spent on each module: And here's the SSL benchmark running modified vmbench on a 4-core 2.5GHz cloud server, all benchmarked servers are running in Where:
The new |
611741a
to
72ddbe0
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Amazing work, I honestly don't have anything aside nitpicking ;)
Thanks a lot for reviewing in late night! ❤️ |
I'm testing this in debug mode just to make sure we haven't made some silly mistakes. I see that the process memory grows aggressively to some point and then flats out; this might be Python's famous memory fragmentation issue. But just in case, I'd like you to see if you can reproduce this locally. Instructions:
So the process' memory usage grows with time. I'm 99% sure that this is just memory fragmentation. But maybe we also need to ensure that it's contained; for instance, it might be a good idea to cap max buffer size when we realloc. In general, I'd appreciate if you take another quick glance over Other than that, the PR is ready :) |
Totally reasonable. Will do, and I'll see if I can find some more tools or ways to check possible memory issues. |
examples/bench/echoserver.py
Outdated
class EchoBufferedProtocol(asyncio.BufferedProtocol): | ||
def connection_made(self, transport): | ||
self.transport = transport | ||
self.buffer = bytearray(256 * 1024) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
self._buffer = bytearray(256 * 1024)
self.buffer = memoryview(self._buffer)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ha! Been there, should have commented - to make sure the echo is true, the buffer needs to be copied, so that next read doesn’t change previous outgoing data which is still pending. With memoryview and bytes again, the benchmark gets slightly slower, therefore it ended up like this now. Thanks anyway! I’ll add comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, right :)
We'll need to add a new API to asyncio 3.8 to tell us when a write()
has completed so that we can re-use the buffer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That’s interesting!
We don't support the new sendfile in uvloop yet. |
BTW, we should merge your additions back to the vmbench project. |
8a0c44c
to
26f36ac
Compare
I could reproduce the memory pattern. The memory increase seems to be more relevant to new SSL connection, rather than repeated echo send and recv. So I tested with I've also reviewed the code, and made a few small changes. (I'll create a separate PR for the vmbench changes) If okay, I'll rebase again and squash all commits. |
go for it! |
a08f0c7
to
5c44111
Compare
@elprans can you take a quick look at this before I merge? |
5c44111
to
c5168a4
Compare
@fantix hey, could you please take a look at the failed CI? |
Sure thing! Sorry been out of office, will check today. |
c5168a4
to
d7f7f17
Compare
Seems to be an unstable test, a retest passed. Tried but didn't reproduce locally, I'll try to find clues in the failing log. |
@asvetlov could you also take a look? This is something that we'll use pretty much as is in asyncio in 3.8. |
Thank you so much, @fantix! 💯🎉🚀 |
Thanks a lot @1st1 😃🍻 |
Huge improvement! Thanks! |
State transition:
Recv/send calling chain:
Reworked flow control:
SSLProtocol
internals (shutdown detail):SSLObject
methods internals:Refs #158,
this is a WIP yet, please kindly wait until ready for review.TODOs:
cdef class
for both performance and readibilityeof_received()
implementationChecksendfile
support