Add filesystem-backed L2 adapter with auto-discovery plugin mechanism#2704
Add filesystem-backed L2 adapter with auto-discovery plugin mechanism#2704ApostaC merged 8 commits intoLMCache:devfrom
Conversation
Summary of ChangesHello, 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 system by introducing a robust filesystem-backed L2 adapter, providing persistent storage for KV cache data. Concurrently, it implements a flexible auto-discovery mechanism for L2 adapters, transforming the architecture into a plug-and-play system. This change streamlines the process of integrating new storage backends and improves the overall extensibility and resilience of the caching layer. 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 significant architectural improvement by adding a filesystem-backed L2 adapter and refactoring the adapter loading mechanism to a plugin-based auto-discovery system, greatly enhancing modularity. While the implementation of the FSL2Adapter is comprehensive, security concerns have been identified regarding the handling of filesystem paths and permissions. Specifically, the cache directory and files are created with overly permissive default permissions, potentially leading to information disclosure. Additionally, the temporary directory configuration lacks proper sanitization against path traversal and relies on assert for validation, which is insecure. Beyond these security aspects, the review also includes suggestions to improve robustness and correctness, particularly around file I/O and parsing logic.
8f8a4bd to
963902c
Compare
| ) -> None: | ||
| bitmap = Bitmap(len(keys)) | ||
| for i, key in enumerate(keys): | ||
| if key not in self._known_keys: |
There was a problem hiding this comment.
@maobaolong Thanks for the great contribution! But I have a question, it will only be searched from memory index?
There was a problem hiding this comment.
Thanks for the remind, this in memory metadata related data structures should be removed to achieve metadata sharing between nodes.
3fa242c to
97c5757
Compare
|
@chunxiaozheng Thanks for your review, removed all motioned metadata cache purpose data structures. PTAL. |
| _FILE_BACKENDS = ("GDS", "GDS_MT", "POSIX", "HF3FS") | ||
|
|
||
|
|
||
| class NixlStoreL2AdapterConfig(L2AdapterConfigBase): |
There was a problem hiding this comment.
do you want to move this too?
There was a problem hiding this comment.
Yeah thanks for remind me.
ApostaC
left a comment
There was a problem hiding this comment.
Small changes needed. Otherwise LGTM
| """ | ||
| if name in _L2_ADAPTER_FACTORY_REGISTRY: | ||
| raise ValueError(f"L2 adapter factory already registered: {name!r}") | ||
| _L2_ADAPTER_FACTORY_REGISTRY[name] = factory |
There was a problem hiding this comment.
It's better to put the adapter creatio in a separate file instead of in config.py.
Also, let's have a more "constrained" signature for the factory callable. Something like Callable[[L2AdapterConfigBase], L2AdapterInterface]?
|
|
||
| # Self-register config type and adapter factory | ||
| register_l2_adapter_type("mock", MockL2AdapterConfig) | ||
| register_l2_adapter_factory("mock", lambda config, **kwargs: MockL2Adapter(config)) |
There was a problem hiding this comment.
| register_l2_adapter_factory("mock", lambda config, **kwargs: MockL2Adapter(config)) | |
| register_l2_adapter_factory("mock", lambda config: MockL2Adapter(config)) |
There was a problem hiding this comment.
we also need to change the nixl l2 adapters's config and initialization to use the new code
ApostaC
left a comment
There was a problem hiding this comment.
Did another pass on fs_l2_adapter.py, please see the comments.
Additionally, can we add the UT for this as well?
There was a problem hiding this comment.
Please add a customized report_status() implementation for the FSL2Adapter.
| if file_path.exists(): | ||
| bitmap.set(i) |
There was a problem hiding this comment.
This is a FS I/O operation. Do we want to use aiofiles, making it async, and running it in the asyncio loop?
| "FSL2Adapter failed to store %s", | ||
| file_path, | ||
| ) | ||
| if await aiofiles.os.path.exists(tmp_path): |
There was a problem hiding this comment.
If self._key_to_file_and_tmp_path(key) raises before the tmp_path is initialized, here may have another NameError.
There was a problem hiding this comment.
add tmp_path not none check
| Fields: | ||
| - base_path: directory for storing KV cache files. | ||
| - relative_tmp_dir: optional relative sub-dir for | ||
| temp files (same as fs_connector_relative_tmp_dir). |
There was a problem hiding this comment.
Can we have the docstring for read_ahead_size and use_odirect as well?
|
Oh, almost forget. Please update the docs as well, thanks! |
|
@ApostaC @sammshen @chunxiaozheng Thanks for the previous review, addressed all the suggested comments from you, PTAL. |
ApostaC
left a comment
There was a problem hiding this comment.
Should be some final comments. Otherwise LGTM.
There was a problem hiding this comment.
Thanks for the doc update, can we also update the https://docs.lmcache.ai/mp/l2_storage.html to tell people how to use the new FS L2 adapter (i.e., how to write the config in the commandline)?
| if l1_memory_desc is not None: | ||
| config.l1_memory_desc = l1_memory_desc # type: ignore[attr-defined] |
There was a problem hiding this comment.
This is a bit hacky. Let's pass the l1_memory_desc all the way down to the L2 adapter's __init__ function.
This means that we probably need to change the definition of L2AdapterFactory from Callable[["L2AdapterConfigBase"], "L2AdapterInterface"] to Callable[["L2AdapterConfigBase", "L1MemoryDesc"], "L2AdapterInterface"]
| logger = init_logger(__name__) | ||
|
|
||
| # Type alias for factory callables | ||
| L2AdapterFactory = Callable[["L2AdapterConfigBase"], "L2AdapterInterface"] |
There was a problem hiding this comment.
| L2AdapterFactory = Callable[["L2AdapterConfigBase"], "L2AdapterInterface"] | |
| L2AdapterFactory = Callable[["L2AdapterConfigBase", "L1MemoryDesc"], "L2AdapterInterface"] |
| self.backend = backend | ||
| self.backend_params = backend_params | ||
| self.pool_size = pool_size | ||
| self.l1_memory_desc: Optional[L1MemoryDesc] = None |
There was a problem hiding this comment.
We don't need this if we are going to pass the l1_memory_desc via the factory's arguments.
| l1_memory_desc = getattr(config, "l1_memory_desc", None) | ||
| if l1_memory_desc is None: | ||
| raise ValueError("l1_memory_desc is required to create a NixlStoreL2Adapter.") |
There was a problem hiding this comment.
We don't need this if we are going to pass the l1_memory_desc via the factory's arguments.
677e756 to
07d0abc
Compare
|
@ApostaC Thanks for the new review, addressed the comment, PTAL. |
| ``fs`` -- File-system backed storage | ||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
|
|
||
| A pure file-system L2 adapter using async I/O. Does not require NIXL. |
There was a problem hiding this comment.
why do you need to specify does not require NIXL here?
There was a problem hiding this comment.
Remove it. Added since before this fs adapter, there is only nixl adapter.
|
I rebased #2642 to follow this PR. Either one can be merged first |
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 from LMCache#2704. - 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 - Move MockL2AdapterConfig to mock_l2_adapter.py (per LMCache#2704 pattern) - Update __init__.py to use pkgutil auto-discovery Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.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 from LMCache#2704. - 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 - Move MockL2AdapterConfig to mock_l2_adapter.py (per LMCache#2704 pattern) - Update __init__.py to use pkgutil auto-discovery
Signed-off-by: baoloongmao <baoloongmao@tencent.com>
Signed-off-by: baoloongmao <baoloongmao@tencent.com>
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 from LMCache#2704. - 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 - Move MockL2AdapterConfig to mock_l2_adapter.py (per LMCache#2704 pattern) - Update __init__.py to use pkgutil auto-discovery
Signed-off-by: baoloongmao <baoloongmao@tencent.com>
e1f8407 to
94d509f
Compare
Signed-off-by: baoloongmao <baoloongmao@tencent.com>
Signed-off-by: baoloongmao <baoloongmao@tencent.com>
…LMCache#2704) * Add filesystem-backed L2 adapter with auto-discovery plugin mechanism Signed-off-by: baoloongmao <baoloongmao@tencent.com> Signed-off-by: Aaron Wu <aaron.wu@dell.com>
…LMCache#2704) * Add filesystem-backed L2 adapter with auto-discovery plugin mechanism Signed-off-by: baoloongmao <baoloongmao@tencent.com>
…LMCache#2704) * Add filesystem-backed L2 adapter with auto-discovery plugin mechanism Signed-off-by: baoloongmao <baoloongmao@tencent.com>
What this PR does / why we need it:
Add
FSL2Adapter— a filesystem-backed L2 adapter that stores KV cache chunksas raw tensor files on disk. This enables persistent L2 caching across restarts.
What changed:
fs_l2_adapter.py: async disk I/O via aiofiles, atomic writes (tmp + rename),O_DIRECT support, read-ahead, and startup file scanning.
config.pyand__init__.pyto use a registry +pkgutil.iter_modulesauto-discovery mechanism. Adding a new L2 adapter no longer requires modifying any
existing code — just drop a new module in the
l2_adapters/package.MockL2AdapterConfigandFSL2AdapterConfiginto their respective adaptermodules for self-contained registration.
Config options (all align with FSConnector naming):
{ "type": "fs", "base_path": "/path/to/l2_cache", "relative_tmp_dir": ".tmp", "read_ahead_size": 65536, "use_odirect": true }Test
Special notes for your reviewers:
If applicable: