[Southbound]: Create a Native Protocol for MP and non-MP#2642
[Southbound]: Create a Native Protocol for MP and non-MP#2642sammshen merged 2 commits intoLMCache:devfrom
Conversation
Summary of ChangesHello @sammshen, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly enhances the LMCache project by establishing a robust and extensible architecture for native storage backend integrations. By abstracting common patterns like threading, eventfd-based notifications, and submission/completion queues into a base class, it simplifies the development of new high-performance connectors. The existing Redis client serves as a concrete example of this new framework, showcasing how to leverage C++ for efficient, non-blocking I/O operations while seamlessly integrating with Python's asynchronous capabilities. Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Changelog
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request introduces a well-designed abstraction for native storage backends, refactoring the existing Redis client into a more generic and extensible "connector" architecture. This is an excellent improvement for maintainability and will make it easier to add new storage backends in the future. The new ConnectorBase provides a solid foundation, and the new README.md is very helpful for developers. My review focuses on a few areas for improvement regarding safety checks that were missed during the refactoring and some code cleanup.
| py::memoryview mv = memviews[i].cast<py::memoryview>(); | ||
| py::buffer_info info = py::buffer(mv).request(); | ||
| bufs.push_back(info.ptr); | ||
| lens.push_back(static_cast<size_t>(info.size)); |
There was a problem hiding this comment.
The previous implementation of the pybind wrapper included validation to ensure the provided memoryview was 1-dimensional and byte-addressable. This validation is missing here. This is a critical safety check to prevent potential memory corruption or crashes if an incorrectly shaped buffer is passed from Python. Please add these checks back.
A similar change is needed in bind_submit_batch_set on lines 94-97.
py::memoryview mv = memviews[i].cast<py::memoryview>();
py::buffer_info info = py::buffer(mv).request();
if (info.ndim != 1) {
throw std::runtime_error("memoryview must be 1D");
}
if (info.itemsize != 1) {
throw std::runtime_error("memoryview must be byte addressable");
}
bufs.push_back(info.ptr);
lens.push_back(static_cast<size_t>(info.size));There was a problem hiding this comment.
I agree with this opinion. Good to have for future debugging.
Since, info.size is number of elements, not bytes.
| ### 3. create python wrapper | ||
|
|
||
| inherit from `connector_client_base.py` which provides asyncio integration, future management, sync/async methods. | ||
| reference: `lmcache/v1/storage_backend/resp_client.py` |
There was a problem hiding this comment.
The file path referenced here is outdated due to the refactoring. lmcache/v1/storage_backend/resp_client.py has been moved and refactored. The correct reference should be to the new resp_client.py wrapper.
| reference: `lmcache/v1/storage_backend/resp_client.py` | |
| reference: `lmcache/v1/storage_backend/native_clients/resp_client.py` |
|
Impressive! I will review in this night. Thanks @sammshen |
|
try to unify with MP mode: #2569 |
DongDongJu
left a comment
There was a problem hiding this comment.
@sammshen Great work. it seems you made the gem.
I left few comments.
| instantiated in connector_base.h and further overridden by custom storage | ||
| connectors | ||
| */ | ||
| class IStorageConnector { |
There was a problem hiding this comment.
What is the I meaning in this class name?
There was a problem hiding this comment.
InterfaceStorageConnector, sorry if it is unclear
| py::memoryview mv = memviews[i].cast<py::memoryview>(); | ||
| py::buffer_info info = py::buffer(mv).request(); | ||
| bufs.push_back(info.ptr); | ||
| lens.push_back(static_cast<size_t>(info.size)); |
There was a problem hiding this comment.
I agree with this opinion. Good to have for future debugging.
Since, info.size is number of elements, not bytes.
|
|
||
| # future_id -> (Future, op_name) | ||
| # we support both types of futures since we only their basic interface | ||
| self._pending: Dict[ |
There was a problem hiding this comment.
It seems does not hold references to the submitted memoryviews or their backing objects.
when a task awaiting a Future is cancelled, the awaited Future can be cancelled too, and the coroutine can unwind, dropping the last Python references while C++ worker threads still hold raw pointers.
Can we store keepalive refs per future_id, e.g. _pending[fid] = (fut, op, tuple(bufs))?
And we should only drop those refs after completion is handled or native shutdown is fully done.
There was a problem hiding this comment.
great point, added extra lifetime to the pending operations that will be freed either on failure or on completion
|
|
||
| RedisConnector::~RedisConnector() { close(); } | ||
|
|
||
| WorkerConn RedisConnector::create_connection() { |
There was a problem hiding this comment.
what happened if this func was failed?
There was a problem hiding this comment.
good point, right now we just stay dead but we can add reconnection logic
maobaolong
left a comment
There was a problem hiding this comment.
@sammshen Could you also add a pure c++ implemented fs connector?
| @@ -0,0 +1,297 @@ | |||
| # SPDX-License-Identifier: Apache-2.0 | |||
There was a problem hiding this comment.
@ApostaC the new adapter for native MP mode adapters
|
Thanks for review @maobaolong. I think this should be a follow up PR |
| # Cleanup | ||
| # ------------------------------------------------------------------- | ||
|
|
||
| def close(self) -> None: |
There was a problem hiding this comment.
if self._closed:
return
self._closed = TrueSuggest to add the closed flag to avoid double close.
maobaolong
left a comment
There was a problem hiding this comment.
Left a minor nit, otherwise, this PR looks good.
| ) | ||
|
|
||
|
|
||
| register_l2_adapter_type("resp", RESPL2AdapterConfig) |
There was a problem hiding this comment.
I submitted a PR to do a refactor, after that, add a new coming l2_adapter, we never need to change any existing file.
ApostaC
left a comment
There was a problem hiding this comment.
Please make the fixes following our offline discussions. Give an approve here.
460f985 to
341bf0f
Compare
Refactors the C++ Redis connector into a generic storage backend framework and adds an L2 adapter bridge for MP mode. Follows the plugin/auto-discovery pattern. - Generalize csrc/redis -> csrc/storage_backends with ConnectorBase<T> template, IStorageConnector interface, and pybind macro - Add NativeConnectorL2Adapter bridging any native connector to L2 - Add RESPL2AdapterConfig with self-registration (plugin pattern) - Refactor ConnectorClientBase as generic base for non-MP mode
maobaolong
left a comment
There was a problem hiding this comment.
LGTM @sammshen Thanks for this great feature, will extend some fs native adapter base on your effort!
Signed-off-by: Samuel Shen <slshen@tensormesh.ai>
Refactors the C++ Redis connector into a generic storage backend framework and adds an L2 adapter bridge for MP mode. Follows the plugin/auto-discovery pattern. - Generalize csrc/redis -> csrc/storage_backends with ConnectorBase<T> template, IStorageConnector interface, and pybind macro - Add NativeConnectorL2Adapter bridging any native connector to L2 - Add RESPL2AdapterConfig with self-registration (plugin pattern) - Refactor ConnectorClientBase as generic base for non-MP mode
Refactors the C++ Redis connector into a generic storage backend framework and adds an L2 adapter bridge for MP mode. Follows the plugin/auto-discovery pattern. - Generalize csrc/redis -> csrc/storage_backends with ConnectorBase<T> template, IStorageConnector interface, and pybind macro - Add NativeConnectorL2Adapter bridging any native connector to L2 - Add RESPL2AdapterConfig with self-registration (plugin pattern) - Refactor ConnectorClientBase as generic base for non-MP mode Signed-off-by: Aaron Wu <aaron.wu@dell.com>
Refactors the C++ Redis connector into a generic storage backend framework and adds an L2 adapter bridge for MP mode. Follows the plugin/auto-discovery pattern. - Generalize csrc/redis -> csrc/storage_backends with ConnectorBase<T> template, IStorageConnector interface, and pybind macro - Add NativeConnectorL2Adapter bridging any native connector to L2 - Add RESPL2AdapterConfig with self-registration (plugin pattern) - Refactor ConnectorClientBase as generic base for non-MP mode Signed-off-by: baoloongmao <baoloongmao@tencent.com>
Refactors the C++ Redis connector into a generic storage backend framework and adds an L2 adapter bridge for MP mode. Follows the plugin/auto-discovery pattern. - Generalize csrc/redis -> csrc/storage_backends with ConnectorBase<T> template, IStorageConnector interface, and pybind macro - Add NativeConnectorL2Adapter bridging any native connector to L2 - Add RESPL2AdapterConfig with self-registration (plugin pattern) - Refactor ConnectorClientBase as generic base for non-MP mode
Refactors the C++ Redis connector into a generic storage backend framework and adds an L2 adapter bridge for MP mode. Follows the plugin/auto-discovery pattern. - Generalize csrc/redis -> csrc/storage_backends with ConnectorBase<T> template, IStorageConnector interface, and pybind macro - Add NativeConnectorL2Adapter bridging any native connector to L2 - Add RESPL2AdapterConfig with self-registration (plugin pattern) - Refactor ConnectorClientBase as generic base for non-MP mode
Implementation of #2632 as a generalization of the strategies employed in #2541