Skip to content
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

PYTHON-4860 - Async client should use asyncio.Lock and asyncio.Condition #1934

Merged
merged 11 commits into from
Oct 17, 2024

Conversation

NoahStapp
Copy link
Contributor

No description provided.

@NoahStapp NoahStapp changed the title PYTHON-4725 Async client should use tasks for SDAM instead of threads PYTHON-4860 - Async client should use asyncio.Lock and asyncio.Condition Oct 16, 2024
@NoahStapp
Copy link
Contributor Author

Relies on #1928.


if __name__ == "__main__":
unittest.main()
# # Copyright 2024-present MongoDB, Inc.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that we're using the stdlib Lock + Condition, we should be able to remove these tests as they're copied from the asyncio test suite: https://github.com/python/cpython/blob/v3.13.0rc2/Lib/test/test_asyncio/test_locks.py.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However, the two issues fixed in 3.13 are still present on older versions of Python: (python/cpython#111693 and python/cpython#112202)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we'll need to polyfill those fixes then

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, vendoring asyncio.locks seems like the best option here until we drop 3.12 support 😅

@NoahStapp
Copy link
Contributor Author

The test failures appear to be linux-specific, investigating.

pymongo/lock.py Outdated
@@ -11,15 +11,17 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Lock and Condition classes vendored from https://github.com/python/cpython/blob/main/Lib/asyncio/locks.py
to port 3.13 fixes to older versions of Python."""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to add attribution in THIRD_PARTY_NOTICES

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And we should make it a separate file with a note that it can one day be removed when we drop 3.12 support.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which parts of the CPython license do we need? Just the PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 section?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@@ -1,513 +0,0 @@
# Copyright 2024-present MongoDB, Inc.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we're vendoring the 3.13 locks, we'll need to keep this test file.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couldn't we only run these tests on older versions of Python?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. By the way did you investigate the bugs to confirm that we actually need to vendor the locks? I'm wondering if we can just use the built in classes and accept any potential built in bugs.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After looking, python/cpython#111693 seems fine.

python/cpython#112202 would could result in deadlocks or timeouts so it seems serious enough to warrant vendoring.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

python/cpython#111693 doesn't seem like an issue agreed.

@@ -1019,15 +1018,13 @@ def __init__(
# The first portion of the wait queue.
# Enforces: maxPoolSize
# Also used for: clearing the wait queue
self.size_cond = _ACondition(threading.Condition(_lock))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's move these back since the Condition vars are defined alongside the variables they protect as well as the explanatory comments.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch!

pymongo/lock.py Outdated
self.release() # type: ignore[attr-defined]


class Lock(_ContextManagerMixin, _LoopBoundMixin):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that we're directly vendoring, we should split the vendored code into its own file. then we can do something like this:

if sys.version_info >= (3, 13):
    Lock = asyncio.Lock
    Condition = asyncio.Condition
else
    Lock = pymongo._asyncio_lock.Lock
    Condition = pymongo._asyncio_lock.Condition

This way we're not mixing vendored code with our own.

pymongo/lock.py Outdated
import weakref
from typing import Any, Callable, Optional, TypeVar
from asyncio import TimeoutError, wait_for
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest using asyncio.TimeoutError to avoid shadowing the builtin TimeoutError.

pymongo/lock.py Outdated
@@ -28,6 +33,14 @@

_T = TypeVar("_T")

# Needed to support 3.13 asyncio fixes in older versions of Python
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add https://github.com/python/cpython/issues/112202 here? That's the most important bugfix we need.

lock: threading.Lock, condition_class: Optional[Any] = None
) -> threading.Condition:
"""Represents a threading.Condition."""
if condition_class:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sigh, I can't believe we still have to write code for condition_class even though it's never used. I reopened https://jira.mongodb.org/browse/PYTHON-1149.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I wasn't sure if we actually still used it, removing it entirely would be great.

Copy link
Member

@blink1073 blink1073 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@NoahStapp NoahStapp merged commit a23003f into mongodb:async-improvements Oct 17, 2024
26 checks passed
@NoahStapp NoahStapp deleted the PYTHON-4860 branch October 17, 2024 13:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants