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,624 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # Standard
3
+ from concurrent.futures import Future, TimeoutError
4
+ from typing import Any, Callable, List, Optional, Sequence, Set
5
+ import asyncio
6
+ import threading
7
+ import time
8
+
9
+ # First Party
10
+ from lmcache.logging import init_logger
11
+ from lmcache.observability import LMCStatsMonitor, PrometheusLogger
12
+ from lmcache.utils import CacheEngineKey, _lmcache_nvtx_annotate
13
+ from lmcache.v1.config import LMCacheEngineConfig
14
+ from lmcache.v1.exceptions import IrrecoverableException
15
+ from lmcache.v1.memory_management import MemoryObj
16
+ from lmcache.v1.metadata import LMCacheMetadata
17
+ from lmcache.v1.storage_backend.abstract_backend import StorageBackendInterface
18
+ from lmcache.v1.storage_backend.connector import CreateConnector
19
+ from lmcache.v1.storage_backend.connector.base_connector import RemoteConnector
20
+ from lmcache.v1.storage_backend.local_cpu_backend import LocalCPUBackend
21
+ from lmcache.v1.storage_backend.naive_serde import CreateSerde
22
+
23
+ logger = init_logger(__name__)
24
+
25
+
26
+ class RemoteBackend(StorageBackendInterface):
27
+ def __init__(
28
+ self,
29
+ config: LMCacheEngineConfig,
30
+ metadata: LMCacheMetadata,
31
+ loop: asyncio.AbstractEventLoop,
32
+ local_cpu_backend: Optional[LocalCPUBackend],
33
+ dst_device: str = "cuda",
34
+ plugin_name: Optional[str] = None,
35
+ ):
36
+ super().__init__(dst_device=dst_device)
37
+ self.put_tasks: Set[CacheEngineKey] = set()
38
+ self.lock = threading.Lock()
39
+
40
+ self.plugin_name = plugin_name
41
+
42
+ # Determine if we're using legacy remote_url or new plugin-based approach
43
+ if plugin_name is not None:
44
+ # Using plugin-based approach
45
+ self.remote_url = f"plugin://{plugin_name}"
46
+ logger.info(f"Creating RemoteBackend for plugin: {plugin_name}")
47
+ else:
48
+ # Legacy remote_url approach
49
+ if config.remote_url is None:
50
+ raise ValueError(
51
+ "remote_url must be provided when not using plugin_name"
52
+ )
53
+ self.remote_url = config.remote_url
54
+
55
+ self.local_cpu_backend = local_cpu_backend
56
+
57
+ self.loop = loop
58
+ self.config = config
59
+ self.metadata = metadata
60
+
61
+ # Re-establish connection only when the connection
62
+ # has been lost for 10 secs
63
+ self.connection: Optional[RemoteConnector] = None
64
+ self.min_reconnect_interval = 10
65
+ self.failure_time = -1000000.0
66
+ self.init_connection()
67
+
68
+ assert config.remote_serde is not None
69
+ self.serializer, self.deserializer = CreateSerde(
70
+ config.remote_serde, metadata, config
71
+ )
72
+
73
+ # Precompute MLA mode status
74
+ self._mla_worker_id_as0_mode = (
75
+ config.get_extra_config_value(
76
+ "remote_enable_mla_worker_id_as0", metadata.use_mla
77
+ )
78
+ and metadata.use_mla
79
+ and metadata.world_size > 1
80
+ and metadata.worker_id != 0
81
+ )
82
+ logger.info(f"metadata={metadata}")
83
+ logger.info(
84
+ f"Connected to remote storage at {config.remote_url}, "
85
+ f"remote_mla_worker_id_as_0 mode: {self._mla_worker_id_as0_mode}"
86
+ )
87
+
88
+ # TODO(Jiayi): If we want to have cache admission policies,
89
+ # we must make decision (whether to send or not) at the local side
90
+
91
+ self.stats_monitor = LMCStatsMonitor.GetOrCreate()
92
+
93
+ # NOTE: Health monitoring is now handled at the LMCacheEngine level
94
+ # through HealthMonitor. RemoteBackend no longer manages its own
95
+ # health monitoring. The HealthMonitor in LMCacheEngine will
96
+ # register RemoteBackendHealthCheck for each RemoteBackend.
97
+
98
+ self._setup_metrics()
99
+
100
+ self._get_blocking_failed_count = 0
101
+ self._put_failed_count = 0
102
+
103
+ def _setup_metrics(self):
104
+ prometheus_logger = PrometheusLogger.GetInstanceOrNone()
105
+ if prometheus_logger is not None:
106
+ prometheus_logger.remote_put_task_num.set_function(
107
+ lambda: len(self.put_tasks)
108
+ )
109
+ prometheus_logger.get_blocking_failed_count.set_function(
110
+ lambda: self._get_blocking_failed_count
111
+ )
112
+ prometheus_logger.put_failed_count.set_function(
113
+ lambda: self._put_failed_count
114
+ )
115
+
116
+ def __str__(self):
117
+ return self.__class__.__name__
118
+
119
+ def init_connection(self):
120
+ # Initialize connection
121
+ if self.connection is not None:
122
+ return
123
+ if (time.time() - self.failure_time) < self.min_reconnect_interval:
124
+ logger.warning(
125
+ "Connection will not be re-established yet "
126
+ "since it has not been long enough since "
127
+ "the last failure"
128
+ )
129
+ return
130
+ try:
131
+ # Determine the URL to use for connection
132
+ if self.plugin_name is not None:
133
+ # Using plugin-based approach
134
+ # Create a virtual URL that the adapter can recognize
135
+ url = f"plugin://{self.plugin_name}"
136
+ logger.info(f"Creating connector for plugin: {self.plugin_name}")
137
+ else:
138
+ # Legacy remote_url approach
139
+ if self.config.remote_url is None:
140
+ raise ValueError(
141
+ "remote_url must be provided when not using plugin_name"
142
+ )
143
+ url = self.config.remote_url
144
+
145
+ self.connection = CreateConnector(
146
+ url,
147
+ self.loop,
148
+ self.local_cpu_backend,
149
+ self.config,
150
+ self.metadata,
151
+ plugin_name=self.plugin_name,
152
+ )
153
+ logger.info(f"Connection initialized/re-established at {url}")
154
+ except IrrecoverableException:
155
+ logger.error("Irrecoverable error during connection initialization")
156
+ raise
157
+ except Exception as e:
158
+ with self.lock:
159
+ self.failure_time = time.time()
160
+ logger.warning(f"Failed to initialize/re-establish remote connection: {e}")
161
+ self.connection = None
162
+
163
+ def contains(self, key: CacheEngineKey, pin: bool = False) -> bool:
164
+ if self.connection is None:
165
+ logger.warning("Connection is None in contains, returning False")
166
+ return False
167
+
168
+ # For MLA worker id as 0 mode, use worker_id 0
169
+ if self._mla_worker_id_as0_mode:
170
+ key = key.with_new_worker_id(0)
171
+
172
+ try:
173
+ if self.config.extra_config is not None and self.config.extra_config.get(
174
+ "use_exists_sync", False
175
+ ):
176
+ return self.connection.exists_sync(key)
177
+ else:
178
+ future = asyncio.run_coroutine_threadsafe(
179
+ self.connection.exists(key), self.loop
180
+ )
181
+ res = future.result()
182
+ return res
183
+ except Exception as e:
184
+ logger.warning(f"Remote connection failed in contains: {e}")
185
+ logger.warning("Returning False")
186
+ return False
187
+
188
+ def batched_contains(
189
+ self,
190
+ keys: List[CacheEngineKey],
191
+ pin: bool = False,
192
+ ) -> int:
193
+ if self.connection is None:
194
+ logger.warning("Connection is None in batched_contains, returning 0")
195
+ return 0
196
+
197
+ if not self.connection.support_batched_contains():
198
+ return super().batched_contains(keys, pin)
199
+
200
+ if self._mla_worker_id_as0_mode:
201
+ keys = [key.with_new_worker_id(0) for key in keys]
202
+
203
+ try:
204
+ return self.connection.batched_contains(keys)
205
+ except Exception as e:
206
+ logger.warning(f"Remote connection failed in batched_contains: {e}")
207
+ return 0
208
+
209
+ def exists_in_put_tasks(self, key: CacheEngineKey) -> bool:
210
+ with self.lock:
211
+ return key in self.put_tasks
212
+
213
+ def put_callback(self, future: Future, key: CacheEngineKey):
214
+ with self.lock:
215
+ self.put_tasks.discard(key)
216
+ try:
217
+ future.result()
218
+ except Exception as e:
219
+ self._put_failed_count += 1
220
+ logger.error(f"Put task failed for key {key}: {e}")
221
+
222
+ def submit_put_task(
223
+ self,
224
+ key: CacheEngineKey,
225
+ memory_obj: MemoryObj,
226
+ on_complete_callback: Optional[Callable[[CacheEngineKey], None]] = None,
227
+ ) -> Future:
228
+ """
229
+ Submit a put task to store KV cache to remote storage asynchronously.
230
+
231
+ :param on_complete_callback: Optional callback invoked after the remote
232
+ write completes. Callback exceptions are caught and logged.
233
+ """
234
+
235
+ def create_immediate_empty_future() -> Future:
236
+ f: Future = Future()
237
+ f.set_result(None)
238
+ return f
239
+
240
+ if self.connection is None:
241
+ logger.warning("Connection is None in submit_put_task, returning None")
242
+ return create_immediate_empty_future()
243
+
244
+ # If MLA worker id as 0 mode is enabled, skip put tasks
245
+ if self._mla_worker_id_as0_mode:
246
+ return create_immediate_empty_future()
247
+
248
+ if self.exists_in_put_tasks(key):
249
+ return create_immediate_empty_future()
250
+
251
+ memory_obj.ref_count_up()
252
+
253
+ with self.lock:
254
+ self.put_tasks.add(key)
255
+
256
+ compressed_memory_obj = self.serializer.serialize(memory_obj)
257
+ memory_obj.ref_count_down()
258
+
259
+ def put_done_callback(f: Future) -> None:
260
+ self.put_callback(f, key)
261
+ if on_complete_callback is not None:
262
+ try:
263
+ on_complete_callback(key)
264
+ except Exception as e:
265
+ logger.warning(f"on_complete_callback failed for key {key}: {e}")
266
+
267
+ # NOTE: No need to do error handling here
268
+ # since the `future` is never waited
269
+ future = asyncio.run_coroutine_threadsafe(
270
+ self.connection.put(key, compressed_memory_obj), self.loop
271
+ )
272
+ future.add_done_callback(put_done_callback)
273
+ return future
274
+
275
+ def batched_put_callback(self, future: Future, keys: List[CacheEngineKey]):
276
+ """
277
+ Callback function for batched put tasks.
278
+ """
279
+ with self.lock:
280
+ self.put_tasks.difference_update(keys)
281
+
282
+ def batched_submit_put_task(
283
+ self,
284
+ keys: Sequence[CacheEngineKey],
285
+ memory_objs: List[MemoryObj],
286
+ transfer_spec: Any = None,
287
+ on_complete_callback: Optional[Callable[[CacheEngineKey], None]] = None,
288
+ ) -> None:
289
+ """
290
+ Submit batched put tasks to store KV caches to remote storage.
291
+
292
+ :param on_complete_callback: Optional callback invoked once per key
293
+ after that key's write completes (not once per batch).
294
+ """
295
+ if self.connection is None:
296
+ logger.warning(
297
+ "Connection is None in batched_submit_put_task, returning None"
298
+ )
299
+ return
300
+ if self.connection.support_batched_put():
301
+ if self._mla_worker_id_as0_mode:
302
+ return
303
+
304
+ # First, increment reference counts for all objects
305
+ for memory_obj in memory_objs:
306
+ memory_obj.ref_count_up()
307
+
308
+ compressed_memory_objs = []
309
+ try:
310
+ for memory_obj in memory_objs:
311
+ compressed_memory_objs.append(self.serializer.serialize(memory_obj))
312
+ finally:
313
+ # Always decrement reference counts for all objects,
314
+ # regardless of whether serialization succeeded or failed
315
+ for memory_obj in memory_objs:
316
+ memory_obj.ref_count_down()
317
+
318
+ def batched_done_callback(f: Future) -> None:
319
+ self.batched_put_callback(f, list(keys))
320
+ # Invoke per-key callback for each key in the batch
321
+ if on_complete_callback is not None:
322
+ for key in keys:
323
+ try:
324
+ on_complete_callback(key)
325
+ except Exception as e:
326
+ logger.warning(
327
+ f"on_complete_callback failed for key {key}: {e}"
328
+ )
329
+
330
+ future = asyncio.run_coroutine_threadsafe(
331
+ self.connection.batched_put(keys, compressed_memory_objs), # type: ignore
332
+ self.loop,
333
+ )
334
+ future.add_done_callback(batched_done_callback)
335
+ else:
336
+ for key, memory_obj in zip(keys, memory_objs, strict=False):
337
+ self.submit_put_task(
338
+ key, memory_obj, on_complete_callback=on_complete_callback
339
+ )
340
+
341
+ @_lmcache_nvtx_annotate
342
+ def get_blocking(
343
+ self,
344
+ key: CacheEngineKey,
345
+ ) -> Optional[MemoryObj]:
346
+ """
347
+ Blocking get function.
348
+ """
349
+ # Check if local_cpu_backend is available (required for memory allocation)
350
+ if self.local_cpu_backend is None:
351
+ logger.warning(
352
+ "local_cpu_backend is None in get_blocking "
353
+ "(likely scheduler role), returning None"
354
+ )
355
+ return None
356
+
357
+ if self.connection is None:
358
+ logger.warning("Connection is None in get_blocking, returning None")
359
+ return None
360
+ # For MLA worker id as 0 mode, use worker_id 0
361
+ if self._mla_worker_id_as0_mode:
362
+ key = key.with_new_worker_id(0)
363
+ t1 = time.perf_counter()
364
+ future = asyncio.run_coroutine_threadsafe(self.connection.get(key), self.loop)
365
+
366
+ try:
367
+ memory_obj = future.result(self.config.blocking_timeout_secs)
368
+ except Exception as e:
369
+ if isinstance(e, TimeoutError):
370
+ logger.warning("get blocking timeout, trigger cancel the future task")
371
+ future.cancel()
372
+ logger.warning("Error occurred in get_blocking: %s, return None", e)
373
+ memory_obj = None
374
+
375
+ t2 = time.perf_counter()
376
+ self.stats_monitor.update_interval_remote_time_to_get_sync((t2 - t1) * 1000)
377
+ if memory_obj is None:
378
+ self._get_blocking_failed_count += 1
379
+ return None
380
+ decompressed_memory_obj = self.deserializer.deserialize(memory_obj)
381
+ t3 = time.perf_counter()
382
+ logger.debug(
383
+ "Get takes %.6f msec, deserialization takes %.6f msec",
384
+ (t2 - t1) * 1000,
385
+ (t3 - t2) * 1000,
386
+ )
387
+ return decompressed_memory_obj
388
+
389
+ @property
390
+ def get_blocking_failed_count(self):
391
+ return self._get_blocking_failed_count
392
+
393
+ @property
394
+ def put_failed_count(self):
395
+ return self._put_failed_count
396
+
397
+ def batched_get_blocking(
398
+ self,
399
+ keys: List[CacheEngineKey],
400
+ ) -> List[Optional[MemoryObj]]:
401
+ # Check if local_cpu_backend is available (required for memory allocation)
402
+ if self.local_cpu_backend is None:
403
+ logger.warning(
404
+ "local_cpu_backend is None in batched_get_blocking "
405
+ "(likely scheduler role), returning None list"
406
+ )
407
+ return [None] * len(keys)
408
+
409
+ if self.connection is None:
410
+ logger.warning("Connection is None in batched_get_blocking, returning None")
411
+ return [None] * len(keys)
412
+
413
+ # For MLA worker id as 0 mode, use worker_id 0
414
+ if self._mla_worker_id_as0_mode:
415
+ keys = [key.with_new_worker_id(0) for key in keys]
416
+
417
+ t1 = time.perf_counter()
418
+ # batched get
419
+ if self.connection.support_batched_get():
420
+ future = asyncio.run_coroutine_threadsafe(
421
+ self.connection.batched_get(keys), self.loop
422
+ )
423
+ try:
424
+ memory_objs = future.result(self.config.blocking_timeout_secs)
425
+ except Exception as e:
426
+ if isinstance(e, TimeoutError):
427
+ logger.warning(
428
+ "batched get blocking timeout, trigger cancel the future task"
429
+ )
430
+ future.cancel()
431
+ else:
432
+ logger.warning(
433
+ f"Error occurred in batched_get_blocking: {e}, "
434
+ f"returning None list"
435
+ )
436
+ memory_objs = [None] * len(keys)
437
+ else:
438
+ remote_backend_individual_get_stats: dict[
439
+ CacheEngineKey, dict[str, float]
440
+ ] = {}
441
+ retrieve_stats = self.stats_monitor.get_current_retrieve_stats()
442
+ if retrieve_stats is not None:
443
+ retrieve_stats.detailed_metrics[
444
+ "remote_backend_individual_get_stats"
445
+ ] = remote_backend_individual_get_stats
446
+
447
+ futures = [
448
+ asyncio.run_coroutine_threadsafe(self.connection.get(key), self.loop)
449
+ for key in keys
450
+ ]
451
+ memory_objs = []
452
+ failed = False
453
+ for fut in futures:
454
+ if not failed:
455
+ try:
456
+ memory_obj = fut.result(self.config.blocking_timeout_secs)
457
+ except Exception as e:
458
+ failed = True
459
+ if isinstance(e, TimeoutError):
460
+ logger.warning(
461
+ "get blocking timeout, trigger cancel the future task"
462
+ )
463
+ fut.cancel()
464
+ else:
465
+ logger.warning(
466
+ f"Error occurred in get_blocking: {e}, returning None"
467
+ )
468
+ memory_obj = None
469
+ memory_objs.append(memory_obj)
470
+ else:
471
+ memory_objs.append(None)
472
+ fut.cancel()
473
+
474
+ t2 = time.perf_counter()
475
+ duration = t2 - t1
476
+ self.stats_monitor.update_interval_remote_time_to_get_sync(duration * 1000)
477
+
478
+ retrieve_stats = self.stats_monitor.get_current_retrieve_stats()
479
+ if retrieve_stats is not None:
480
+ retrieve_stats.detailed_metrics[
481
+ "remote_backend_batched_get_blocking_time"
482
+ ] = (
483
+ retrieve_stats.detailed_metrics.get(
484
+ "remote_backend_batched_get_blocking_time", 0.0
485
+ )
486
+ + duration
487
+ )
488
+ decompressed_memory_objs: list[Optional[MemoryObj]] = []
489
+ error_happened = False
490
+ for memory_obj in memory_objs:
491
+ if memory_obj is None:
492
+ error_happened = True
493
+ decompressed_memory_objs.append(None)
494
+ else:
495
+ decompressed_memory_objs.append(
496
+ self.deserializer.deserialize(memory_obj)
497
+ )
498
+ if error_happened:
499
+ self._get_blocking_failed_count += 1
500
+
501
+ assert len(decompressed_memory_objs) == len(keys), (
502
+ f"keys length: {len(keys)}, "
503
+ f"decompressed memory objs length: {len(decompressed_memory_objs)}"
504
+ )
505
+ return decompressed_memory_objs
506
+
507
+ async def support_batched_async_contains(self) -> bool:
508
+ return (
509
+ self.connection is not None
510
+ and self.connection.support_batched_async_contains()
511
+ )
512
+
513
+ async def batched_async_contains(
514
+ self,
515
+ lookup_id: str,
516
+ keys: list[CacheEngineKey],
517
+ pin: bool = False,
518
+ ) -> int:
519
+ if self.connection is None:
520
+ logger.warning("Connection is None in batched_async_contains, returning 0")
521
+ return 0
522
+ if self._mla_worker_id_as0_mode:
523
+ keys = [key.with_new_worker_id(0) for key in keys]
524
+
525
+ try:
526
+ assert self.connection.support_batched_async_contains(), (
527
+ f"Connector {self.connection} does not support batched async contains"
528
+ )
529
+ # warning, this timeout will not actually stop the
530
+ # scheduler from waiting for the result
531
+ return await asyncio.wait_for(
532
+ self.connection.batched_async_contains(lookup_id, keys, pin),
533
+ self.config.blocking_timeout_secs,
534
+ )
535
+ except asyncio.TimeoutError:
536
+ logger.warning("batched_async_contains timed out")
537
+ return 0
538
+ except Exception as e:
539
+ logger.warning(f"Error occurred in batched_async_contains: {e}")
540
+ return 0
541
+
542
+ async def support_batched_get_non_blocking(self) -> bool:
543
+ return (
544
+ self.connection is not None
545
+ and self.connection.support_batched_get_non_blocking()
546
+ )
547
+
548
+ async def batched_get_non_blocking(
549
+ self,
550
+ lookup_id: str,
551
+ keys: List[CacheEngineKey],
552
+ transfer_spec: Any = None,
553
+ ) -> List[MemoryObj]:
554
+ # Check if local_cpu_backend is available (required for memory allocation)
555
+ if self.local_cpu_backend is None:
556
+ logger.warning(
557
+ "local_cpu_backend is None in batched_get_non_blocking "
558
+ "(likely scheduler role), returning empty list"
559
+ )
560
+ return []
561
+
562
+ if self.connection is None:
563
+ logger.warning(
564
+ "Connection is None in batched_get_non_blocking, returning empty list"
565
+ )
566
+ return []
567
+ try:
568
+ # warning, this timeout will not actually stop the
569
+ # scheduler from waiting for the result
570
+ return await asyncio.wait_for(
571
+ self.connection.batched_get_non_blocking(lookup_id, keys),
572
+ self.config.blocking_timeout_secs,
573
+ )
574
+ except asyncio.TimeoutError:
575
+ logger.warning("batched_get_non_blocking timed out")
576
+ return []
577
+ except Exception as e:
578
+ logger.warning(f"Error occurred in batched_get_non_blocking: {e}")
579
+ return []
580
+
581
+ def pin(self, key: CacheEngineKey) -> bool:
582
+ logger.debug(
583
+ "Remote backend does not support pin. "
584
+ "This method is a no-op and will return True."
585
+ )
586
+ return True
587
+
588
+ def unpin(self, key: CacheEngineKey) -> bool:
589
+ logger.debug(
590
+ "Remote backend does not support unpin. "
591
+ "This method is a no-op and will return True."
592
+ )
593
+ return True
594
+
595
+ def remove(self, key, force=True):
596
+ if self.connection is None:
597
+ logger.warning("Connection is None in remove, returning False")
598
+ return False
599
+
600
+ try:
601
+ return self.connection.remove_sync(key)
602
+ except Exception as e:
603
+ logger.exception(
604
+ f"Failed to remove key {key} from remote backend, error: {e}"
605
+ )
606
+ return False
607
+
608
+ def get_allocator_backend(self):
609
+ assert self.local_cpu_backend is not None, (
610
+ "local_cpu_backend is required for get_allocator_backend, "
611
+ "should not be called in scheduler role"
612
+ )
613
+ return self.local_cpu_backend
614
+
615
+ def close(self):
616
+ try:
617
+ assert self.connection is not None
618
+ future = asyncio.run_coroutine_threadsafe(
619
+ self.connection.close(), self.loop
620
+ )
621
+ future.result()
622
+ logger.info("Remote backend closed.")
623
+ except Exception as e:
624
+ logger.warning(f"Error occurred when closing remote connection: {e}")