lmcache-cli 0.4.5.dev0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (399) hide show
  1. lmcache/__init__.py +84 -0
  2. lmcache/_version.py +24 -0
  3. lmcache/cli/__init__.py +1 -0
  4. lmcache/cli/commands/__init__.py +34 -0
  5. lmcache/cli/commands/base.py +157 -0
  6. lmcache/cli/commands/bench/__init__.py +557 -0
  7. lmcache/cli/commands/bench/engine_bench/__init__.py +1 -0
  8. lmcache/cli/commands/bench/engine_bench/config.py +245 -0
  9. lmcache/cli/commands/bench/engine_bench/interactive/__init__.py +274 -0
  10. lmcache/cli/commands/bench/engine_bench/interactive/config.json +10 -0
  11. lmcache/cli/commands/bench/engine_bench/interactive/schema.py +352 -0
  12. lmcache/cli/commands/bench/engine_bench/interactive/state.py +327 -0
  13. lmcache/cli/commands/bench/engine_bench/interactive/terminal.py +291 -0
  14. lmcache/cli/commands/bench/engine_bench/progress.py +145 -0
  15. lmcache/cli/commands/bench/engine_bench/request_sender.py +232 -0
  16. lmcache/cli/commands/bench/engine_bench/stats.py +275 -0
  17. lmcache/cli/commands/bench/engine_bench/workloads/__init__.py +153 -0
  18. lmcache/cli/commands/bench/engine_bench/workloads/base.py +122 -0
  19. lmcache/cli/commands/bench/engine_bench/workloads/long_doc_permutator.py +435 -0
  20. lmcache/cli/commands/bench/engine_bench/workloads/long_doc_qa.py +281 -0
  21. lmcache/cli/commands/bench/engine_bench/workloads/multi_round_chat.py +337 -0
  22. lmcache/cli/commands/bench/engine_bench/workloads/random_prefill.py +178 -0
  23. lmcache/cli/commands/describe.py +310 -0
  24. lmcache/cli/commands/kvcache.py +133 -0
  25. lmcache/cli/commands/mock.py +75 -0
  26. lmcache/cli/commands/ping.py +113 -0
  27. lmcache/cli/commands/query/__init__.py +155 -0
  28. lmcache/cli/commands/query/prompt.py +134 -0
  29. lmcache/cli/commands/query/request.py +357 -0
  30. lmcache/cli/commands/server.py +99 -0
  31. lmcache/cli/commands/tool/__init__.py +63 -0
  32. lmcache/cli/commands/tool/cache_simulator.py +113 -0
  33. lmcache/cli/commands/trace/__init__.py +505 -0
  34. lmcache/cli/commands/trace/dispatch.py +249 -0
  35. lmcache/cli/commands/trace/driver.py +372 -0
  36. lmcache/cli/commands/trace/stats.py +289 -0
  37. lmcache/cli/documents/lmcache.txt +11 -0
  38. lmcache/cli/main.py +42 -0
  39. lmcache/cli/metrics/__init__.py +29 -0
  40. lmcache/cli/metrics/formatter.py +171 -0
  41. lmcache/cli/metrics/handler.py +94 -0
  42. lmcache/cli/metrics/metrics.py +161 -0
  43. lmcache/cli/metrics/section.py +77 -0
  44. lmcache/connections.py +173 -0
  45. lmcache/integration/__init__.py +2 -0
  46. lmcache/integration/base_service_factory.py +165 -0
  47. lmcache/integration/request_telemetry/__init__.py +1 -0
  48. lmcache/integration/request_telemetry/base.py +51 -0
  49. lmcache/integration/request_telemetry/factory.py +113 -0
  50. lmcache/integration/request_telemetry/fastapi.py +109 -0
  51. lmcache/integration/request_telemetry/noop.py +35 -0
  52. lmcache/integration/sglang/__init__.py +2 -0
  53. lmcache/integration/sglang/sglang_adapter.py +326 -0
  54. lmcache/integration/sglang/utils.py +39 -0
  55. lmcache/integration/vllm/__init__.py +1 -0
  56. lmcache/integration/vllm/lmcache_connector_v1.py +213 -0
  57. lmcache/integration/vllm/lmcache_connector_v1_085.py +150 -0
  58. lmcache/integration/vllm/lmcache_mp_connector_0180.py +1072 -0
  59. lmcache/integration/vllm/tests/test_mm_hash_utils.py +112 -0
  60. lmcache/integration/vllm/utils.py +433 -0
  61. lmcache/integration/vllm/vllm_multi_process_adapter.py +1090 -0
  62. lmcache/integration/vllm/vllm_service_factory.py +339 -0
  63. lmcache/integration/vllm/vllm_v1_adapter.py +1713 -0
  64. lmcache/logging.py +107 -0
  65. lmcache/native_storage_ops.pyi +230 -0
  66. lmcache/non_cuda_equivalents.py +1424 -0
  67. lmcache/observability.py +1958 -0
  68. lmcache/storage_backend/serde/__init__.py +1 -0
  69. lmcache/storage_backend/serde/cachegen_basics.py +210 -0
  70. lmcache/storage_backend/serde/cachegen_decoder.py +207 -0
  71. lmcache/storage_backend/serde/cachegen_encoder.py +394 -0
  72. lmcache/storage_backend/serde/serde.py +75 -0
  73. lmcache/tools/__init__.py +1 -0
  74. lmcache/tools/cache_simulator/README.md +392 -0
  75. lmcache/tools/cache_simulator/__init__.py +1 -0
  76. lmcache/tools/cache_simulator/docs/simulate_example.png +0 -0
  77. lmcache/tools/cache_simulator/docs/sweep_example.png +0 -0
  78. lmcache/tools/cache_simulator/gen_bench_dataset.py +360 -0
  79. lmcache/tools/cache_simulator/lru_cache.py +124 -0
  80. lmcache/tools/cache_simulator/plot_hit_rate.py +231 -0
  81. lmcache/tools/cache_simulator/simulator.py +795 -0
  82. lmcache/tools/controller_benchmark/README.md +161 -0
  83. lmcache/tools/controller_benchmark/__init__.py +1 -0
  84. lmcache/tools/controller_benchmark/__main__.py +331 -0
  85. lmcache/tools/controller_benchmark/benchmark.py +660 -0
  86. lmcache/tools/controller_benchmark/config.py +44 -0
  87. lmcache/tools/controller_benchmark/constants.py +10 -0
  88. lmcache/tools/controller_benchmark/handlers/__init__.py +46 -0
  89. lmcache/tools/controller_benchmark/handlers/admit.py +52 -0
  90. lmcache/tools/controller_benchmark/handlers/base.py +47 -0
  91. lmcache/tools/controller_benchmark/handlers/deregister.py +49 -0
  92. lmcache/tools/controller_benchmark/handlers/evict.py +52 -0
  93. lmcache/tools/controller_benchmark/handlers/heartbeat.py +56 -0
  94. lmcache/tools/controller_benchmark/handlers/p2p_lookup.py +47 -0
  95. lmcache/tools/controller_benchmark/handlers/register.py +56 -0
  96. lmcache/tools/mp_status_viewer/__init__.py +1 -0
  97. lmcache/tools/mp_status_viewer/__main__.py +95 -0
  98. lmcache/usage_context.py +417 -0
  99. lmcache/utils.py +665 -0
  100. lmcache/v1/__init__.py +2 -0
  101. lmcache/v1/api_server/__init__.py +2 -0
  102. lmcache/v1/api_server/__main__.py +537 -0
  103. lmcache/v1/basic_check.py +112 -0
  104. lmcache/v1/cache_controller/__init__.py +9 -0
  105. lmcache/v1/cache_controller/commands/__init__.py +15 -0
  106. lmcache/v1/cache_controller/commands/base.py +35 -0
  107. lmcache/v1/cache_controller/commands/full_sync.py +49 -0
  108. lmcache/v1/cache_controller/config.py +176 -0
  109. lmcache/v1/cache_controller/controller_manager.py +535 -0
  110. lmcache/v1/cache_controller/controllers/__init__.py +11 -0
  111. lmcache/v1/cache_controller/controllers/full_sync_tracker.py +473 -0
  112. lmcache/v1/cache_controller/controllers/kv_controller.py +439 -0
  113. lmcache/v1/cache_controller/controllers/registration_controller.py +282 -0
  114. lmcache/v1/cache_controller/executor.py +463 -0
  115. lmcache/v1/cache_controller/frontend/static/css/style.css +201 -0
  116. lmcache/v1/cache_controller/frontend/static/img/logo.png +0 -0
  117. lmcache/v1/cache_controller/frontend/static/index.html +234 -0
  118. lmcache/v1/cache_controller/frontend/static/js/controller_app.js +660 -0
  119. lmcache/v1/cache_controller/full_sync_sender.py +475 -0
  120. lmcache/v1/cache_controller/locks.py +149 -0
  121. lmcache/v1/cache_controller/message.py +828 -0
  122. lmcache/v1/cache_controller/observability.py +208 -0
  123. lmcache/v1/cache_controller/utils.py +679 -0
  124. lmcache/v1/cache_controller/worker.py +665 -0
  125. lmcache/v1/cache_engine.py +2058 -0
  126. lmcache/v1/cache_interface.py +19 -0
  127. lmcache/v1/check/__init__.py +74 -0
  128. lmcache/v1/check/check_mode_gen.py +86 -0
  129. lmcache/v1/check/check_mode_test_l2_adapter.py +284 -0
  130. lmcache/v1/check/check_mode_test_remote.py +155 -0
  131. lmcache/v1/check/check_mode_test_storage_manager.py +142 -0
  132. lmcache/v1/check/utils.py +571 -0
  133. lmcache/v1/compute/__init__.py +2 -0
  134. lmcache/v1/compute/attention/__init__.py +0 -0
  135. lmcache/v1/compute/attention/abstract.py +39 -0
  136. lmcache/v1/compute/attention/flash_attn.py +129 -0
  137. lmcache/v1/compute/attention/flash_infer_sparse.py +284 -0
  138. lmcache/v1/compute/attention/metadata.py +85 -0
  139. lmcache/v1/compute/attention/utils.py +14 -0
  140. lmcache/v1/compute/blend/__init__.py +7 -0
  141. lmcache/v1/compute/blend/blender.py +168 -0
  142. lmcache/v1/compute/blend/metadata.py +34 -0
  143. lmcache/v1/compute/blend/utils.py +63 -0
  144. lmcache/v1/compute/models/__init__.py +0 -0
  145. lmcache/v1/compute/models/base.py +141 -0
  146. lmcache/v1/compute/models/llama.py +9 -0
  147. lmcache/v1/compute/models/qwen3.py +24 -0
  148. lmcache/v1/compute/models/utils.py +68 -0
  149. lmcache/v1/compute/positional_encoding.py +199 -0
  150. lmcache/v1/config.py +848 -0
  151. lmcache/v1/config_base.py +848 -0
  152. lmcache/v1/distributed/api.py +248 -0
  153. lmcache/v1/distributed/config.py +321 -0
  154. lmcache/v1/distributed/error.py +64 -0
  155. lmcache/v1/distributed/eviction.py +192 -0
  156. lmcache/v1/distributed/eviction_policy/__init__.py +21 -0
  157. lmcache/v1/distributed/eviction_policy/factory.py +27 -0
  158. lmcache/v1/distributed/eviction_policy/lru.py +244 -0
  159. lmcache/v1/distributed/eviction_policy/noop.py +50 -0
  160. lmcache/v1/distributed/internal_api.py +170 -0
  161. lmcache/v1/distributed/l1_manager.py +835 -0
  162. lmcache/v1/distributed/l2_adapters/__init__.py +67 -0
  163. lmcache/v1/distributed/l2_adapters/base.py +360 -0
  164. lmcache/v1/distributed/l2_adapters/config.py +385 -0
  165. lmcache/v1/distributed/l2_adapters/factory.py +205 -0
  166. lmcache/v1/distributed/l2_adapters/fs_l2_adapter.py +747 -0
  167. lmcache/v1/distributed/l2_adapters/fs_native_l2_adapter.py +167 -0
  168. lmcache/v1/distributed/l2_adapters/mock_l2_adapter.py +516 -0
  169. lmcache/v1/distributed/l2_adapters/mooncake_store_l2_adapter.py +135 -0
  170. lmcache/v1/distributed/l2_adapters/native_connector_l2_adapter.py +468 -0
  171. lmcache/v1/distributed/l2_adapters/native_plugin_l2_adapter.py +199 -0
  172. lmcache/v1/distributed/l2_adapters/nixl_store_dynamic_l2_adapter.py +831 -0
  173. lmcache/v1/distributed/l2_adapters/nixl_store_l2_adapter.py +983 -0
  174. lmcache/v1/distributed/l2_adapters/plugin_l2_adapter.py +210 -0
  175. lmcache/v1/distributed/l2_adapters/resp_l2_adapter.py +176 -0
  176. lmcache/v1/distributed/memory_manager.py +179 -0
  177. lmcache/v1/distributed/storage_controller.py +39 -0
  178. lmcache/v1/distributed/storage_controllers/__init__.py +43 -0
  179. lmcache/v1/distributed/storage_controllers/eviction_controller.py +242 -0
  180. lmcache/v1/distributed/storage_controllers/prefetch_controller.py +830 -0
  181. lmcache/v1/distributed/storage_controllers/prefetch_policy.py +193 -0
  182. lmcache/v1/distributed/storage_controllers/store_controller.py +452 -0
  183. lmcache/v1/distributed/storage_controllers/store_policy.py +213 -0
  184. lmcache/v1/distributed/storage_manager.py +532 -0
  185. lmcache/v1/event_manager.py +145 -0
  186. lmcache/v1/exceptions/__init__.py +16 -0
  187. lmcache/v1/gpu_connector/__init__.py +126 -0
  188. lmcache/v1/gpu_connector/gpu_connectors.py +1906 -0
  189. lmcache/v1/gpu_connector/gpu_ops.py +85 -0
  190. lmcache/v1/gpu_connector/hpu_connector.py +326 -0
  191. lmcache/v1/gpu_connector/mock_gpu_connector.py +67 -0
  192. lmcache/v1/gpu_connector/utils.py +890 -0
  193. lmcache/v1/gpu_connector/xpu_connectors.py +916 -0
  194. lmcache/v1/health_monitor/__init__.py +1 -0
  195. lmcache/v1/health_monitor/base.py +587 -0
  196. lmcache/v1/health_monitor/checks/__init__.py +1 -0
  197. lmcache/v1/health_monitor/checks/remote_backend_check.py +304 -0
  198. lmcache/v1/health_monitor/constants.py +36 -0
  199. lmcache/v1/internal_api_server/__init__.py +0 -0
  200. lmcache/v1/internal_api_server/api_registry.py +59 -0
  201. lmcache/v1/internal_api_server/api_server.py +120 -0
  202. lmcache/v1/internal_api_server/common/__init__.py +1 -0
  203. lmcache/v1/internal_api_server/common/env_api.py +22 -0
  204. lmcache/v1/internal_api_server/common/loglevel_api.py +57 -0
  205. lmcache/v1/internal_api_server/common/metrics_api.py +29 -0
  206. lmcache/v1/internal_api_server/common/periodic_thread_api.py +138 -0
  207. lmcache/v1/internal_api_server/common/run_script_api.py +73 -0
  208. lmcache/v1/internal_api_server/common/thread_api.py +63 -0
  209. lmcache/v1/internal_api_server/controller/__init__.py +1 -0
  210. lmcache/v1/internal_api_server/controller/key_stats_api.py +81 -0
  211. lmcache/v1/internal_api_server/controller/worker_info_api.py +136 -0
  212. lmcache/v1/internal_api_server/utils.py +43 -0
  213. lmcache/v1/internal_api_server/vllm/__init__.py +1 -0
  214. lmcache/v1/internal_api_server/vllm/backend_api.py +221 -0
  215. lmcache/v1/internal_api_server/vllm/bypass_api.py +204 -0
  216. lmcache/v1/internal_api_server/vllm/cache_api.py +895 -0
  217. lmcache/v1/internal_api_server/vllm/chunk_statistics_api.py +141 -0
  218. lmcache/v1/internal_api_server/vllm/conf_api.py +147 -0
  219. lmcache/v1/internal_api_server/vllm/freeze_api.py +172 -0
  220. lmcache/v1/internal_api_server/vllm/hot_cache_api.py +184 -0
  221. lmcache/v1/internal_api_server/vllm/inference_api.py +65 -0
  222. lmcache/v1/internal_api_server/vllm/load_fs_chunks_api.py +320 -0
  223. lmcache/v1/internal_api_server/vllm/lookup_api.py +145 -0
  224. lmcache/v1/internal_api_server/vllm/version_api.py +25 -0
  225. lmcache/v1/kv_layer_groups.py +267 -0
  226. lmcache/v1/lazy_memory_allocator.py +284 -0
  227. lmcache/v1/lookup_client/__init__.py +25 -0
  228. lmcache/v1/lookup_client/abstract_client.py +77 -0
  229. lmcache/v1/lookup_client/async_lookup_message.py +50 -0
  230. lmcache/v1/lookup_client/chunk_statistics_lookup_client.py +200 -0
  231. lmcache/v1/lookup_client/factory.py +251 -0
  232. lmcache/v1/lookup_client/hit_limit_lookup_client.py +86 -0
  233. lmcache/v1/lookup_client/lmcache_async_lookup_client.py +407 -0
  234. lmcache/v1/lookup_client/lmcache_lookup_client.py +285 -0
  235. lmcache/v1/lookup_client/lmcache_lookup_client_bypass.py +99 -0
  236. lmcache/v1/lookup_client/mooncake_lookup_client.py +87 -0
  237. lmcache/v1/lookup_client/record_strategies/__init__.py +77 -0
  238. lmcache/v1/lookup_client/record_strategies/base.py +327 -0
  239. lmcache/v1/lookup_client/record_strategies/file_hash.py +130 -0
  240. lmcache/v1/lookup_client/record_strategies/memory_bloom_filter.py +81 -0
  241. lmcache/v1/manager.py +539 -0
  242. lmcache/v1/memory_management.py +2619 -0
  243. lmcache/v1/metadata.py +114 -0
  244. lmcache/v1/mp_observability/AGENTS.override.md +21 -0
  245. lmcache/v1/mp_observability/README.md +204 -0
  246. lmcache/v1/mp_observability/config.py +340 -0
  247. lmcache/v1/mp_observability/event.py +100 -0
  248. lmcache/v1/mp_observability/event_bus.py +313 -0
  249. lmcache/v1/mp_observability/otel_init.py +145 -0
  250. lmcache/v1/mp_observability/subscribers/__init__.py +28 -0
  251. lmcache/v1/mp_observability/subscribers/logging/__init__.py +19 -0
  252. lmcache/v1/mp_observability/subscribers/logging/l1.py +56 -0
  253. lmcache/v1/mp_observability/subscribers/logging/l2.py +73 -0
  254. lmcache/v1/mp_observability/subscribers/logging/lookup_hash.py +209 -0
  255. lmcache/v1/mp_observability/subscribers/logging/mp_server.py +90 -0
  256. lmcache/v1/mp_observability/subscribers/logging/sm.py +59 -0
  257. lmcache/v1/mp_observability/subscribers/metrics/__init__.py +20 -0
  258. lmcache/v1/mp_observability/subscribers/metrics/l0_lifecycle.py +290 -0
  259. lmcache/v1/mp_observability/subscribers/metrics/l1.py +55 -0
  260. lmcache/v1/mp_observability/subscribers/metrics/l1_lifecycle.py +166 -0
  261. lmcache/v1/mp_observability/subscribers/metrics/l2.py +121 -0
  262. lmcache/v1/mp_observability/subscribers/metrics/sm.py +69 -0
  263. lmcache/v1/mp_observability/subscribers/tracing/__init__.py +12 -0
  264. lmcache/v1/mp_observability/subscribers/tracing/mp_server.py +333 -0
  265. lmcache/v1/mp_observability/subscribers/tracing/span_registry.py +148 -0
  266. lmcache/v1/mp_observability/trace/__init__.py +50 -0
  267. lmcache/v1/mp_observability/trace/codecs.py +255 -0
  268. lmcache/v1/mp_observability/trace/decorator.py +147 -0
  269. lmcache/v1/mp_observability/trace/format.py +132 -0
  270. lmcache/v1/mp_observability/trace/lifecycle.py +83 -0
  271. lmcache/v1/mp_observability/trace/reader.py +167 -0
  272. lmcache/v1/mp_observability/trace/recorder.py +300 -0
  273. lmcache/v1/multiprocess/__init__.py +0 -0
  274. lmcache/v1/multiprocess/affinity_pool.py +102 -0
  275. lmcache/v1/multiprocess/blend_server_v2.py +891 -0
  276. lmcache/v1/multiprocess/config.py +253 -0
  277. lmcache/v1/multiprocess/custom_types.py +281 -0
  278. lmcache/v1/multiprocess/futures.py +194 -0
  279. lmcache/v1/multiprocess/gpu_context.py +511 -0
  280. lmcache/v1/multiprocess/http_server.py +235 -0
  281. lmcache/v1/multiprocess/mp_runtime_plugin_launcher.py +130 -0
  282. lmcache/v1/multiprocess/mq.py +732 -0
  283. lmcache/v1/multiprocess/protocol.py +86 -0
  284. lmcache/v1/multiprocess/protocols/README.md +213 -0
  285. lmcache/v1/multiprocess/protocols/__init__.py +127 -0
  286. lmcache/v1/multiprocess/protocols/base.py +89 -0
  287. lmcache/v1/multiprocess/protocols/blend.py +109 -0
  288. lmcache/v1/multiprocess/protocols/blend_v2.py +57 -0
  289. lmcache/v1/multiprocess/protocols/controller.py +53 -0
  290. lmcache/v1/multiprocess/protocols/debug.py +34 -0
  291. lmcache/v1/multiprocess/protocols/engine.py +146 -0
  292. lmcache/v1/multiprocess/protocols/observability.py +39 -0
  293. lmcache/v1/multiprocess/server.py +1134 -0
  294. lmcache/v1/multiprocess/session.py +190 -0
  295. lmcache/v1/multiprocess/token_hasher.py +441 -0
  296. lmcache/v1/offload_server/__init__.py +17 -0
  297. lmcache/v1/offload_server/abstract_server.py +37 -0
  298. lmcache/v1/offload_server/message.py +30 -0
  299. lmcache/v1/offload_server/zmq_server.py +122 -0
  300. lmcache/v1/periodic_thread.py +579 -0
  301. lmcache/v1/pin_monitor.py +246 -0
  302. lmcache/v1/plugin/__init__.py +0 -0
  303. lmcache/v1/plugin/runtime_plugin_launcher.py +211 -0
  304. lmcache/v1/protocol.py +317 -0
  305. lmcache/v1/rpc/__init__.py +17 -0
  306. lmcache/v1/rpc/transport.py +105 -0
  307. lmcache/v1/rpc/zmq_transport.py +213 -0
  308. lmcache/v1/rpc_utils.py +165 -0
  309. lmcache/v1/server/__init__.py +2 -0
  310. lmcache/v1/server/__main__.py +170 -0
  311. lmcache/v1/server/storage_backend/__init__.py +21 -0
  312. lmcache/v1/server/storage_backend/abstract_backend.py +80 -0
  313. lmcache/v1/server/storage_backend/local_backend.py +75 -0
  314. lmcache/v1/server/utils.py +21 -0
  315. lmcache/v1/standalone/__init__.py +1 -0
  316. lmcache/v1/standalone/__main__.py +583 -0
  317. lmcache/v1/standalone/manager.py +80 -0
  318. lmcache/v1/standalone/standalone_service_factory.py +86 -0
  319. lmcache/v1/storage_backend/__init__.py +313 -0
  320. lmcache/v1/storage_backend/abstract_backend.py +445 -0
  321. lmcache/v1/storage_backend/audit_backend.py +233 -0
  322. lmcache/v1/storage_backend/batched_message_sender.py +222 -0
  323. lmcache/v1/storage_backend/cache_policy/__init__.py +45 -0
  324. lmcache/v1/storage_backend/cache_policy/base_policy.py +87 -0
  325. lmcache/v1/storage_backend/cache_policy/fifo.py +58 -0
  326. lmcache/v1/storage_backend/cache_policy/lfu.py +105 -0
  327. lmcache/v1/storage_backend/cache_policy/lru.py +81 -0
  328. lmcache/v1/storage_backend/cache_policy/mru.py +61 -0
  329. lmcache/v1/storage_backend/connector/__init__.py +443 -0
  330. lmcache/v1/storage_backend/connector/audit_adapter.py +77 -0
  331. lmcache/v1/storage_backend/connector/audit_connector.py +320 -0
  332. lmcache/v1/storage_backend/connector/base_connector.py +379 -0
  333. lmcache/v1/storage_backend/connector/blackhole_adapter.py +21 -0
  334. lmcache/v1/storage_backend/connector/blackhole_connector.py +37 -0
  335. lmcache/v1/storage_backend/connector/eic_adapter.py +31 -0
  336. lmcache/v1/storage_backend/connector/eic_connector.py +757 -0
  337. lmcache/v1/storage_backend/connector/external_adapter.py +79 -0
  338. lmcache/v1/storage_backend/connector/fs_adapter.py +51 -0
  339. lmcache/v1/storage_backend/connector/fs_connector.py +403 -0
  340. lmcache/v1/storage_backend/connector/infinistore_adapter.py +56 -0
  341. lmcache/v1/storage_backend/connector/infinistore_connector.py +177 -0
  342. lmcache/v1/storage_backend/connector/instrumented_connector.py +219 -0
  343. lmcache/v1/storage_backend/connector/lm_adapter.py +31 -0
  344. lmcache/v1/storage_backend/connector/lm_connector.py +176 -0
  345. lmcache/v1/storage_backend/connector/mock_adapter.py +57 -0
  346. lmcache/v1/storage_backend/connector/mock_connector.py +349 -0
  347. lmcache/v1/storage_backend/connector/mooncakestore_adapter.py +43 -0
  348. lmcache/v1/storage_backend/connector/mooncakestore_connector.py +614 -0
  349. lmcache/v1/storage_backend/connector/redis_adapter.py +181 -0
  350. lmcache/v1/storage_backend/connector/redis_connector.py +828 -0
  351. lmcache/v1/storage_backend/connector/s3_adapter.py +59 -0
  352. lmcache/v1/storage_backend/connector/s3_connector.py +699 -0
  353. lmcache/v1/storage_backend/connector/sagemaker_hyperpod_adapter.py +233 -0
  354. lmcache/v1/storage_backend/connector/sagemaker_hyperpod_connector.py +987 -0
  355. lmcache/v1/storage_backend/connector/valkey_adapter.py +114 -0
  356. lmcache/v1/storage_backend/connector/valkey_connector.py +627 -0
  357. lmcache/v1/storage_backend/gds_backend.py +1199 -0
  358. lmcache/v1/storage_backend/job_executor/__init__.py +0 -0
  359. lmcache/v1/storage_backend/job_executor/base_executor.py +34 -0
  360. lmcache/v1/storage_backend/job_executor/pq_executor.py +235 -0
  361. lmcache/v1/storage_backend/local_cpu_backend.py +810 -0
  362. lmcache/v1/storage_backend/local_disk_backend.py +656 -0
  363. lmcache/v1/storage_backend/maru_backend.py +734 -0
  364. lmcache/v1/storage_backend/naive_serde/__init__.py +50 -0
  365. lmcache/v1/storage_backend/naive_serde/cachegen_basics.py +133 -0
  366. lmcache/v1/storage_backend/naive_serde/cachegen_decoder.py +135 -0
  367. lmcache/v1/storage_backend/naive_serde/cachegen_encoder.py +83 -0
  368. lmcache/v1/storage_backend/naive_serde/kivi_serde.py +22 -0
  369. lmcache/v1/storage_backend/naive_serde/naive_serde.py +18 -0
  370. lmcache/v1/storage_backend/naive_serde/serde.py +37 -0
  371. lmcache/v1/storage_backend/native_clients/connector_client_base.py +165 -0
  372. lmcache/v1/storage_backend/native_clients/resp_client.py +35 -0
  373. lmcache/v1/storage_backend/nixl_storage_backend.py +1400 -0
  374. lmcache/v1/storage_backend/p2p_backend.py +788 -0
  375. lmcache/v1/storage_backend/path_sharder.py +117 -0
  376. lmcache/v1/storage_backend/pd_backend.py +646 -0
  377. lmcache/v1/storage_backend/plugins/dax_backend.py +1443 -0
  378. lmcache/v1/storage_backend/plugins/rust_raw_block_backend.py +1361 -0
  379. lmcache/v1/storage_backend/remote_backend.py +624 -0
  380. lmcache/v1/storage_backend/resp_client.py +227 -0
  381. lmcache/v1/storage_backend/storage_backend_listener.py +19 -0
  382. lmcache/v1/storage_backend/storage_manager.py +1352 -0
  383. lmcache/v1/system_detection.py +110 -0
  384. lmcache/v1/token_database.py +551 -0
  385. lmcache/v1/transfer_channel/__init__.py +83 -0
  386. lmcache/v1/transfer_channel/abstract.py +285 -0
  387. lmcache/v1/transfer_channel/mock_memory_channel.py +156 -0
  388. lmcache/v1/transfer_channel/nixl_channel.py +639 -0
  389. lmcache/v1/transfer_channel/py_socket_channel.py +260 -0
  390. lmcache/v1/transfer_channel/transfer_utils.py +63 -0
  391. lmcache/v1/utils/__init__.py +1 -0
  392. lmcache/v1/utils/bloom_filter.py +109 -0
  393. lmcache/v1/utils/cache_utils.py +125 -0
  394. lmcache_cli-0.4.5.dev0.dist-info/METADATA +185 -0
  395. lmcache_cli-0.4.5.dev0.dist-info/RECORD +399 -0
  396. lmcache_cli-0.4.5.dev0.dist-info/WHEEL +5 -0
  397. lmcache_cli-0.4.5.dev0.dist-info/entry_points.txt +2 -0
  398. lmcache_cli-0.4.5.dev0.dist-info/licenses/LICENSE +201 -0
  399. lmcache_cli-0.4.5.dev0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,79 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # First Party
3
+ from lmcache.logging import init_logger
4
+ from lmcache.v1.storage_backend.connector import (
5
+ ConnectorAdapter,
6
+ ConnectorContext,
7
+ parse_remote_url,
8
+ )
9
+ from lmcache.v1.storage_backend.connector.base_connector import RemoteConnector
10
+
11
+ logger = init_logger(__name__)
12
+
13
+
14
+ class ExternalConnectorAdapter(ConnectorAdapter):
15
+ """Adapter for External connectors."""
16
+
17
+ def __init__(self) -> None:
18
+ super().__init__("external://")
19
+
20
+ def create_connector(self, context: ConnectorContext) -> RemoteConnector:
21
+ """
22
+ Create an External connector. This connector stores data
23
+ in the key-value store.
24
+ URL format:
25
+ - external://host:port/module_path/?connector_name=ConnectorName
26
+ Examples:
27
+ - external://host:0/external_log_connector.lmc_external_log_connector/?connector_name=ExternalLogConnector
28
+ """
29
+ logger.info(f"Creating External connector for URL: {context.url}")
30
+ logger.warning(
31
+ "External connector is due for deprecation in release v0.5.0. "
32
+ "Please use the Remote Storage Plugin Framework instead."
33
+ )
34
+ hosts = context.url.split(",")
35
+ if len(hosts) > 1:
36
+ raise ValueError(
37
+ f"Only one host is supported for external connector, but got {hosts}"
38
+ )
39
+
40
+ parse_url = parse_remote_url(context.url)
41
+
42
+ # Get the module path and connector name
43
+ module_path = parse_url.path.strip("/")
44
+ connector_name = parse_url.query_params.get("connector_name", [""])[0]
45
+ if not connector_name:
46
+ raise ValueError(
47
+ "External connector requires 'connector_name' in query parameters"
48
+ )
49
+
50
+ # Lazily import the module and get the connector class
51
+ # Standard
52
+ import importlib
53
+
54
+ try:
55
+ module = importlib.import_module(module_path)
56
+ connector_class = getattr(module, connector_name)
57
+
58
+ # Verify that it's a subclass of RemoteConnector
59
+ if not issubclass(connector_class, RemoteConnector):
60
+ raise TypeError(
61
+ f"{connector_name} must be a subclass of RemoteConnector"
62
+ )
63
+
64
+ # Create the connector instance
65
+ connector = connector_class(
66
+ loop=context.loop,
67
+ local_cpu_backend=context.local_cpu_backend,
68
+ config=context.config,
69
+ )
70
+ logger.info(f"Loaded external connector: {module_path}.{connector_name}")
71
+ return connector
72
+ except ImportError as e:
73
+ raise ImportError(
74
+ f"Could not import module '{module_path}', error: {e}"
75
+ ) from e
76
+ except AttributeError as e:
77
+ raise AttributeError(
78
+ f"Module '{module_path}' has no class '{connector_name}', error: {e}"
79
+ ) from e
@@ -0,0 +1,51 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # First Party
3
+ from lmcache.logging import init_logger
4
+ from lmcache.v1.storage_backend.connector import (
5
+ ConnectorAdapter,
6
+ ConnectorContext,
7
+ extract_plugin_type,
8
+ parse_remote_url,
9
+ )
10
+ from lmcache.v1.storage_backend.connector.base_connector import (
11
+ RemoteConnector,
12
+ )
13
+
14
+ logger = init_logger(__name__)
15
+
16
+ PLUGIN_TYPE = "fs"
17
+
18
+
19
+ class FsConnectorAdapter(ConnectorAdapter):
20
+ """Adapter for Filesystem connectors."""
21
+
22
+ def __init__(self) -> None:
23
+ super().__init__("fs://")
24
+
25
+ def can_parse(self, url: str) -> bool:
26
+ if url.startswith(self.schema):
27
+ return True
28
+ if url.startswith("plugin://"):
29
+ pname = url[len("plugin://") :]
30
+ return extract_plugin_type(pname) == PLUGIN_TYPE
31
+ return False
32
+
33
+ def create_connector(self, context: ConnectorContext) -> RemoteConnector:
34
+ # Local
35
+ from .fs_connector import FSConnector
36
+
37
+ logger.info("Creating FS connector")
38
+
39
+ # Legacy URL mode: extract base_path from URL
40
+ base_paths_str = None
41
+ if context.plugin_name is None:
42
+ parsed = parse_remote_url(context.url)
43
+ base_paths_str = parsed.path
44
+
45
+ return FSConnector(
46
+ context.loop,
47
+ context.local_cpu_backend,
48
+ context.config,
49
+ plugin_name=context.plugin_name,
50
+ base_paths_str=base_paths_str,
51
+ )
@@ -0,0 +1,403 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # Standard
3
+ from pathlib import Path
4
+ from typing import List, Optional, Tuple, no_type_check
5
+ import asyncio
6
+ import os
7
+
8
+ # Third Party
9
+ import aiofiles
10
+ import aiofiles.os
11
+
12
+ # First Party
13
+ from lmcache.logging import init_logger
14
+ from lmcache.utils import CacheEngineKey
15
+ from lmcache.v1.config import LMCacheEngineConfig
16
+ from lmcache.v1.memory_management import MemoryObj
17
+ from lmcache.v1.protocol import RemoteMetadata
18
+ from lmcache.v1.storage_backend.connector.base_connector import RemoteConnector
19
+ from lmcache.v1.storage_backend.local_cpu_backend import LocalCPUBackend
20
+
21
+ logger = init_logger(__name__)
22
+
23
+
24
+ class FSConnector(RemoteConnector):
25
+ """File system based connector that stores data in local files.
26
+
27
+ Data is stored in the following format:
28
+ - Each key is stored as a separate file
29
+ - File content: metadata (remote_metadata_bytes) + serialized data
30
+ """
31
+
32
+ def __init__(
33
+ self,
34
+ loop: asyncio.AbstractEventLoop,
35
+ local_cpu_backend: LocalCPUBackend,
36
+ config: Optional[LMCacheEngineConfig],
37
+ plugin_name: Optional[str] = None,
38
+ base_paths_str: Optional[str] = None,
39
+ ):
40
+ """
41
+ Args:
42
+ loop: Asyncio event loop
43
+ local_cpu_backend: Memory allocator interface
44
+ config: Lmcache engine config
45
+ plugin_name: Plugin instance name
46
+ (e.g. "fs", "fs.primary")
47
+ base_paths_str: Comma-separated base paths
48
+ (legacy, passed from adapter when using
49
+ fs:// URL)
50
+ """
51
+ # initialize base class
52
+ super().__init__(
53
+ local_cpu_backend.config,
54
+ local_cpu_backend.metadata,
55
+ )
56
+
57
+ base_path = base_paths_str
58
+ if base_path is None:
59
+ # Resolve from extra_config
60
+ extra_config = config.extra_config if config else None
61
+ if extra_config is not None:
62
+ key_prefix = plugin_name or "fs"
63
+ base_path = extra_config.get(
64
+ "remote_storage_plugin.%s.base_path" % key_prefix
65
+ )
66
+ if base_path is None:
67
+ if extra_config is not None:
68
+ base_path = extra_config.get("fs_base_path")
69
+ if base_path is None:
70
+ raise ValueError(
71
+ "FS connector requires base_path via URL or extra_config"
72
+ )
73
+
74
+ # Parse comma separated paths
75
+ self.base_paths = (
76
+ [Path(p.strip()) for p in base_path.split(",")]
77
+ if "," in base_path
78
+ else [Path(base_path)]
79
+ )
80
+
81
+ self.loop = loop
82
+ self.local_cpu_backend = local_cpu_backend
83
+
84
+ relative_tmp_dir = (
85
+ None
86
+ if config is None
87
+ else config.get_extra_config_value("fs_connector_relative_tmp_dir", None)
88
+ )
89
+ self.relative_tmp_dir = None
90
+ if relative_tmp_dir is not None:
91
+ self.relative_tmp_dir = Path(relative_tmp_dir)
92
+ assert not self.relative_tmp_dir.is_absolute()
93
+
94
+ self.read_ahead_size = (
95
+ None
96
+ if config is None
97
+ else config.get_extra_config_value("fs_connector_read_ahead_size", None)
98
+ )
99
+
100
+ self.use_odirect = (
101
+ False
102
+ if config is None
103
+ else config.get_extra_config_value("fs_connector_use_odirect", False)
104
+ )
105
+ self.os_disk_bs = 0
106
+ if self.use_odirect:
107
+ # save_chunk_meta is useful if save_unfull_chunk is True, since partial
108
+ # chunk will be saved. When loading partial chunk, we need to know
109
+ # data size and shape. However, chunk meta is short (28 bytes) which
110
+ # is not aligned to disk block size (512 or 4096).
111
+ # Therefore, we disable O_DIRECT if save_chunk_meta is True.
112
+ # TODO: support O_DIRECT for save_chunk_meta by
113
+ # padding meta data to 4096.
114
+ if self.save_chunk_meta:
115
+ logger.warning("Cannot use O_DIRECT if save_chunk_meta enabled.")
116
+ self.use_odirect = False
117
+ else:
118
+ stat = os.statvfs(self.base_paths[0])
119
+ self.os_disk_bs = stat.f_bsize
120
+
121
+ logger.info(
122
+ f"Initialized FSConnector with base paths {self.base_paths}, "
123
+ f"relative tmp dir: {self.relative_tmp_dir}, "
124
+ f"read ahead size: {self.read_ahead_size}, "
125
+ f"use O_DIRECT: {self.use_odirect}"
126
+ )
127
+ # Create directories for all paths
128
+ for path in self.base_paths:
129
+ path.mkdir(parents=True, exist_ok=True)
130
+ if self.relative_tmp_dir is not None:
131
+ (path / self.relative_tmp_dir).mkdir(parents=False, exist_ok=True)
132
+
133
+ def _get_base_path(self, key: CacheEngineKey) -> Path:
134
+ """Get file base path for the given key"""
135
+ if len(self.base_paths) == 1:
136
+ base_path = self.base_paths[0]
137
+ else:
138
+ # Calculate hash value and modulo to select path
139
+ hash_val = abs(key.chunk_hash)
140
+ idx = hash_val % len(self.base_paths)
141
+ base_path = self.base_paths[idx]
142
+
143
+ return base_path
144
+
145
+ def _get_file_name(self, key: CacheEngineKey) -> str:
146
+ return key.to_string().replace("/", "-SEP-") + ".data"
147
+
148
+ def _get_file_path(self, key: CacheEngineKey) -> Path:
149
+ """Get file path for the given key"""
150
+ base_path = self._get_base_path(key)
151
+ file_name = self._get_file_name(key)
152
+ return base_path / file_name
153
+
154
+ def _get_file_and_tmp_path(self, key: CacheEngineKey) -> Tuple[Path, Path]:
155
+ """Get file and tmp path for the given key"""
156
+ base_path = self._get_base_path(key)
157
+ file_name = self._get_file_name(key)
158
+ file_path = base_path / file_name
159
+ if self.relative_tmp_dir is not None:
160
+ tmp_path = base_path / self.relative_tmp_dir / file_name
161
+ else:
162
+ tmp_path = file_path.with_suffix(".tmp")
163
+ return file_path, tmp_path
164
+
165
+ async def exists(self, key: CacheEngineKey) -> bool:
166
+ """Check if key exists in file system"""
167
+ file_path = self._get_file_path(key)
168
+ return await aiofiles.os.path.exists(file_path)
169
+
170
+ def exists_sync(self, key: CacheEngineKey) -> bool:
171
+ """Check if key exists in file system synchronized"""
172
+ file_path = self._get_file_path(key)
173
+ return os.path.exists(file_path)
174
+
175
+ def _get_with_odirect(self, file_path: Path) -> Optional[MemoryObj]:
176
+ """Synchronous direct IO read, executed in a thread."""
177
+ fd = -1
178
+ memory_obj: Optional[MemoryObj] = None
179
+ try:
180
+ memory_obj = self.local_cpu_backend.allocate(
181
+ self.meta_shapes, self.meta_dtypes, self.meta_fmt
182
+ )
183
+ if memory_obj is None:
184
+ logger.debug("Memory allocation failed.")
185
+ return None
186
+
187
+ buffer = memory_obj.byte_array
188
+ size = len(buffer)
189
+
190
+ fblock_aligned = (
191
+ self.os_disk_bs is not None
192
+ and self.os_disk_bs > 0
193
+ and size % self.os_disk_bs == 0
194
+ )
195
+ if not fblock_aligned:
196
+ logger.warning(
197
+ f"Cannot use O_DIRECT for {file_path}, size is not aligned."
198
+ )
199
+ with open(file_path, "rb") as f:
200
+ num_read = f.readinto(buffer)
201
+ else:
202
+ fd = os.open(file_path, os.O_RDONLY | getattr(os, "O_DIRECT", 0))
203
+ with os.fdopen(fd, "rb", buffering=0) as fdo:
204
+ # The fd is now managed by the file object, so we "forget" it
205
+ # to prevent closing it in the finally block.
206
+ fd = -1
207
+ num_read = fdo.readinto(buffer)
208
+
209
+ memory_obj = self.reshape_partial_chunk(memory_obj, num_read)
210
+ return memory_obj
211
+
212
+ except Exception as e:
213
+ logger.error(f"Failed to read from file {file_path}: {str(e)}")
214
+ if memory_obj is not None:
215
+ memory_obj.ref_count_down()
216
+ return None
217
+ finally:
218
+ if fd >= 0:
219
+ try:
220
+ os.close(fd)
221
+ except OSError:
222
+ pass
223
+
224
+ async def get(self, key: CacheEngineKey) -> Optional[MemoryObj]:
225
+ """Get data from file system"""
226
+ file_path = self._get_file_path(key)
227
+
228
+ if self.use_odirect and not self.save_chunk_meta:
229
+ return await self.loop.run_in_executor(
230
+ None, self._get_with_odirect, file_path
231
+ )
232
+
233
+ memory_obj = None
234
+ try:
235
+ async with aiofiles.open(file_path, "rb") as f:
236
+ if self.save_chunk_meta:
237
+ # Read metadata buffer first to get shape, dtype, fmt
238
+ # to be able to allocate memory object for the data and read into it
239
+ md_buffer = bytearray(self.remote_metadata_bytes)
240
+ num_read = await f.readinto(md_buffer)
241
+ if num_read != len(md_buffer):
242
+ raise RuntimeError(
243
+ f"Partial read meta {len(md_buffer)} got {num_read}"
244
+ )
245
+
246
+ # Deserialize metadata and allocate memory
247
+ metadata = RemoteMetadata.deserialize(md_buffer)
248
+ memory_obj = self.local_cpu_backend.allocate(
249
+ metadata.shapes, metadata.dtypes, metadata.fmt
250
+ )
251
+ else:
252
+ memory_obj = self.local_cpu_backend.allocate(
253
+ self.meta_shapes, self.meta_dtypes, self.meta_fmt
254
+ )
255
+ if memory_obj is None:
256
+ logger.debug("Memory allocation failed during async disk load.")
257
+ return None
258
+
259
+ # Read the actual data into allocated memory
260
+ buffer = memory_obj.byte_array
261
+ if self.save_chunk_meta:
262
+ # if save chunk meta, read meta will trigger
263
+ # read ahead if fs supported
264
+ num_read = await f.readinto(buffer)
265
+ if num_read != len(buffer):
266
+ raise RuntimeError(
267
+ f"Partial read data {len(buffer)} got {num_read}"
268
+ )
269
+ else:
270
+ if self.read_ahead_size is None:
271
+ num_read = await f.readinto(buffer)
272
+ else:
273
+ if not isinstance(buffer, memoryview):
274
+ buffer = memoryview(buffer)
275
+
276
+ # trigger read head if fs supported
277
+ num_read_ahead = await f.readinto(
278
+ buffer[: self.read_ahead_size]
279
+ )
280
+ assert num_read_ahead <= self.read_ahead_size
281
+
282
+ # if num_read_ahead == self.read_ahead_size,
283
+ # means there may still be some remaining content
284
+ if num_read_ahead == self.read_ahead_size:
285
+ num_read_tail = await f.readinto(
286
+ buffer[self.read_ahead_size :]
287
+ )
288
+ assert num_read_tail is not None
289
+ num_read = num_read_ahead + num_read_tail
290
+ else:
291
+ num_read = num_read_ahead
292
+ # reshape and check
293
+ assert num_read is not None
294
+ memory_obj = self.reshape_partial_chunk(memory_obj, num_read)
295
+
296
+ return memory_obj
297
+
298
+ except Exception as e:
299
+ if not isinstance(e, FileNotFoundError):
300
+ logger.error(f"Failed to read from file {file_path}: {str(e)}")
301
+ if memory_obj is not None:
302
+ memory_obj.ref_count_down()
303
+ return None
304
+
305
+ def _put_with_odirect(self, file_path: Path, buffer: bytes) -> None:
306
+ fd = -1
307
+ try:
308
+ fd = os.open(
309
+ str(file_path),
310
+ os.O_CREAT | os.O_WRONLY | getattr(os, "O_DIRECT", 0),
311
+ 0o644,
312
+ )
313
+ os.write(fd, buffer)
314
+ except Exception as e:
315
+ logger.error(f"Failed to write to file {file_path}: {e}")
316
+ raise
317
+ finally:
318
+ if fd >= 0:
319
+ try:
320
+ os.close(fd)
321
+ except OSError:
322
+ pass
323
+
324
+ async def put(self, key: CacheEngineKey, memory_obj: MemoryObj):
325
+ """Store data to file system"""
326
+ final_path, temp_path = self._get_file_and_tmp_path(key)
327
+
328
+ try:
329
+ # Prepare metadata
330
+ buffer = memory_obj.byte_array
331
+ metadata = (
332
+ RemoteMetadata(
333
+ len(buffer),
334
+ memory_obj.get_shapes(),
335
+ memory_obj.get_dtypes(),
336
+ memory_obj.get_memory_format(),
337
+ )
338
+ if self.save_chunk_meta
339
+ else None
340
+ )
341
+
342
+ size = len(buffer)
343
+ do_use_odirect = self.use_odirect
344
+ if do_use_odirect:
345
+ fblock_aligned = self.os_disk_bs > 0 and size % self.os_disk_bs == 0
346
+ if not fblock_aligned:
347
+ logger.warning(
348
+ f"Cannot use O_DIRECT for writing size {size}, "
349
+ f"which is not aligned to block size {self.os_disk_bs}."
350
+ )
351
+ do_use_odirect = False
352
+
353
+ if do_use_odirect:
354
+ # Use Direct I/O
355
+ await self.loop.run_in_executor(
356
+ None, self._put_with_odirect, temp_path, buffer
357
+ )
358
+ else:
359
+ # Use standard async I/O
360
+ # Write to file (metadata + data)
361
+ async with aiofiles.open(temp_path, "wb") as f:
362
+ if metadata is not None:
363
+ await f.write(metadata.serialize())
364
+ await f.write(buffer)
365
+
366
+ # Atomically rename temp file to final destination
367
+ await aiofiles.os.replace(temp_path, final_path)
368
+
369
+ except Exception as e:
370
+ logger.error(f"Failed to write file {final_path}: {str(e)}")
371
+ if await aiofiles.os.path.exists(temp_path):
372
+ await aiofiles.os.unlink(temp_path) # Remove corrupted file
373
+ raise
374
+
375
+ def remove_sync(self, key: CacheEngineKey) -> bool:
376
+ """
377
+ Remove the file associated with the given key.
378
+
379
+ Args:
380
+ key: The key to remove.
381
+
382
+ Returns:
383
+ bool: True if the file was successfully removed, False otherwise.
384
+ """
385
+ file_path = self._get_file_path(key)
386
+ try:
387
+ os.remove(file_path)
388
+ return True
389
+ except OSError as e:
390
+ logger.error(f"Failed to remove file {file_path}: {e}")
391
+ return False
392
+
393
+ @no_type_check
394
+ async def list(self) -> List[str]:
395
+ """List all keys in file system"""
396
+ keys = []
397
+ for base_path in self.base_paths:
398
+ keys.extend([f.stem for f in base_path.glob("*.data")])
399
+ return keys
400
+
401
+ async def close(self):
402
+ """Clean up resources"""
403
+ logger.info("Closed the file system connector")
@@ -0,0 +1,56 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # First Party
3
+ from lmcache.logging import init_logger
4
+ from lmcache.v1.storage_backend.connector import (
5
+ ConnectorAdapter,
6
+ ConnectorContext,
7
+ parse_remote_url,
8
+ )
9
+ from lmcache.v1.storage_backend.connector.base_connector import RemoteConnector
10
+
11
+ logger = init_logger(__name__)
12
+
13
+
14
+ class InfinistoreConnectorAdapter(ConnectorAdapter):
15
+ """Adapter for Infinistore connectors."""
16
+
17
+ def __init__(self) -> None:
18
+ super().__init__("infinistore://")
19
+
20
+ def create_connector(self, context: ConnectorContext) -> RemoteConnector:
21
+ # Third Party
22
+ import infinistore
23
+
24
+ # Local
25
+ from .infinistore_connector import InfinistoreConnector
26
+
27
+ logger.info(f"Creating Infinistore connector for URL: {context.url}")
28
+ hosts = context.url.split(",")
29
+ if len(hosts) > 1:
30
+ raise ValueError(
31
+ f"Only one host is supported for infinistore, but got {hosts}"
32
+ )
33
+
34
+ parse_url = parse_remote_url(context.url)
35
+ device_name = parse_url.query_params.get("device", ["mlx5_0"])[0]
36
+
37
+ link_type_str = "LINK_ETHERNET"
38
+ if context.config and context.config.extra_config:
39
+ link_type_str = context.config.extra_config.get(
40
+ "infinistore_link_type", link_type_str
41
+ )
42
+
43
+ link_type_str = link_type_str.upper()
44
+ try:
45
+ link_type = getattr(infinistore, link_type_str)
46
+ except AttributeError as e:
47
+ raise ValueError(f"Invalid link_type: {link_type_str}") from e
48
+
49
+ return InfinistoreConnector(
50
+ host=parse_url.host,
51
+ port=parse_url.port,
52
+ dev_name=device_name,
53
+ link_type=link_type,
54
+ loop=context.loop,
55
+ memory_allocator=context.local_cpu_backend,
56
+ )