Skip to content

Conversation

codemaestro64
Copy link

@codemaestro64 codemaestro64 commented Sep 4, 2025

What was wrong?

Issue #793:

Concurrent read and write operations on the same Yamux stream can interleave, leading to potential data corruption and race conditions.
The YamuxStream class currently lacks a dedicated concurrency lock to ensure safe concurrent read and write access.

How was it fixed?

As the first step toward resolving this, the ReadWriteLock implementation was abstracted into a reusable utility module (stream_muxer/rw_lock.py).
This allows it to be cleanly reused across different parts of the codebase, including yamux and potentially other stream muxers.

To-Do

  • Abstract ReadWriteLock into a reusable module (utils/rw_lock.py)
  • Integrate ReadWriteLock into YamuxStream to prevent concurrent read/write corruption
  • Unit tests
  • Clean up commit history

closes #793

@seetadev
Copy link
Contributor

seetadev commented Sep 4, 2025

@codemaestro64 : Wish if you could study the implementation in mplex stream first: please visit #748. Then start the implementation in yamux stream.

CCing @acul71, who is guiding you on this PR. Adding @Jineshbansal and @lla-dane, who could share reviews as you proceed with the PR.

@@ -80,6 +83,8 @@ def __init__(self, stream_id: int, conn: "Yamux", is_initiator: bool) -> None:
self.send_window = DEFAULT_WINDOW_SIZE
self.recv_window = DEFAULT_WINDOW_SIZE
self.window_lock = trio.Lock()
self.rw_lock = ReadWriteLock
Copy link
Contributor

Choose a reason for hiding this comment

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

Did you forget a () ?

self.rw_lock = ReadWriteLock()

@acul71
Copy link
Contributor

acul71 commented Sep 4, 2025

@codemaestro64, your approach follows the same path Go libp2p took. Go had similar concurrency issues with yamux and initially solved them with read-write locks before optimizing with atomic operations.

Go Implementation Evolution

  1. Initial: Only window locks (like current Python yamux)
  2. Added: Read/write locks (like your PR) - fixed race conditions but caused performance issues
  3. Optimized: Removed locks, used Go atomic operations (go-yamux v2.1.1)

Recommendation

  1. Fix the bug: Add () to ReadWriteLock()
  2. Fix lint - type check issues : ping if you need help
  3. Monitor performance: Benchmark vs current implementation
  4. Future optimization: Research lock-free patterns for Python async

@codemaestro64
Copy link
Author

@codemaestro64 : Wish if you could study the implementation in mplex stream first: please visit #748. Then start the implementation in yamux stream.

CCing @acul71, who is guiding you on this PR. Adding @Jineshbansal and @lla-dane, who could share reviews as you proceed with the PR.

Thank you @seetadev Studied the mplex stream implementation.

@codemaestro64
Copy link
Author

@codemaestro64, your approach follows the same path Go libp2p took. Go had similar concurrency issues with yamux and initially solved them with read-write locks before optimizing with atomic operations.

Go Implementation Evolution

  1. Initial: Only window locks (like current Python yamux)
  2. Added: Read/write locks (like your PR) - fixed race conditions but caused performance issues
  3. Optimized: Removed locks, used Go atomic operations (go-yamux v2.1.1)

Recommendation

  1. Fix the bug: Add () to ReadWriteLock()
  2. Fix lint - type check issues : ping if you need help
  3. Monitor performance: Benchmark vs current implementation
  4. Future optimization: Research lock-free patterns for Python async

Thanks for the detailed feedback, @acul71! I’ve addressed the following from your recommendations:

  1. Fixed the bug by adding () to ReadWriteLock().
  2. Resolved the lint and type check issues.
  3. Ran initial benchmarks to compare performance with the current implementation—atomic operations are indeed more performant and fine-grained than read/write locks, as you noted.

Should I proceed with implementing atomic operations in this PR?

@codemaestro64 codemaestro64 changed the title [WIP] enh/793: add read-write lock to yamuxstream enh/793: add read-write lock to yamuxstream Sep 8, 2025
@codemaestro64 codemaestro64 marked this pull request as ready for review September 8, 2025 12:19
@codemaestro64
Copy link
Author

@acul71 review here

Copy link
Contributor

@acul71 acul71 left a comment

Choose a reason for hiding this comment

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

Hello @codemaestro64 Well done.
Just resolve the pytest_configure and it's good for merge

import pytest


@pytest.fixture
def security_protocol():
return None


def pytest_configure(config):
Copy link
Contributor

@acul71 acul71 Sep 9, 2025

Choose a reason for hiding this comment

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

Did you add this pytest_configure function for debugging?
Is still necessary?
Because I don't like this function to be defined here globally for all test, with specific yamux logging conf.
I think better get rid of this or eventually move it in tests/core/stream_muxer/conftest.py

Copy link
Contributor

Choose a reason for hiding this comment

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

?

Copy link
Author

Choose a reason for hiding this comment

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

Hello @acul71 Yes, the pytest_configure function was added for debugging purposes. It's been removed in the latest commit.

Copy link
Contributor

Choose a reason for hiding this comment

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

Great

…urrent read/write corruption

Introduce a read/write lock abstraction and integrate it into `YamuxStream` so that simultaneous
reads and writes do not interleave, eliminating potential data corruption and race conditions.

Major changes:
- Abstract `ReadWriteLock` into its own util module
- Integrate locking into YamuxStream for `write` operations
- Ensure tests pass for lock correctness
- Fix lint & type issues discovered during review

Closes libp2p#793
@codemaestro64 codemaestro64 force-pushed the enhancement/yamuxstream-lock branch from 03b2d30 to c5a2836 Compare September 13, 2025 08:14
@seetadev
Copy link
Contributor

@codemaestro64 : Great effort. Could you please reply to @acul71 's feedback. Also, please resolve the CI/Cd issues.

@acul71 : Thank you for reviewing the PR and for sharing detailed feedback. Appreciate your great support as always.

@seetadev
Copy link
Contributor

@codemaestro64 : Please also add a test suite and newsfragment. Looking forward to final review soon.

@codemaestro64
Copy link
Author

@codemaestro64 : Please also add a test suite and newsfragment. Looking forward to final review soon.

Hi @seetadev These have already been done

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.

Enhancement: Add concurrency lock to YamuxStream to prevent data corruption
3 participants