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,50 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # Standard
3
+ from typing import Optional, Tuple
4
+
5
+ # First Party
6
+ from lmcache.v1.config import LMCacheEngineConfig
7
+ from lmcache.v1.metadata import LMCacheMetadata
8
+ from lmcache.v1.storage_backend.naive_serde.cachegen_decoder import CacheGenDeserializer
9
+ from lmcache.v1.storage_backend.naive_serde.cachegen_encoder import CacheGenSerializer
10
+ from lmcache.v1.storage_backend.naive_serde.kivi_serde import (
11
+ KIVIDeserializer,
12
+ KIVISerializer,
13
+ )
14
+ from lmcache.v1.storage_backend.naive_serde.naive_serde import (
15
+ NaiveDeserializer,
16
+ NaiveSerializer,
17
+ )
18
+ from lmcache.v1.storage_backend.naive_serde.serde import Deserializer, Serializer
19
+
20
+
21
+ def CreateSerde(
22
+ serde_type: str,
23
+ metadata: LMCacheMetadata,
24
+ config: LMCacheEngineConfig,
25
+ ) -> Tuple[Serializer, Deserializer]:
26
+ s: Optional[Serializer] = None
27
+ d: Optional[Deserializer] = None
28
+
29
+ if serde_type == "naive":
30
+ s, d = NaiveSerializer(), NaiveDeserializer()
31
+ elif serde_type == "kivi":
32
+ s, d = KIVISerializer(), KIVIDeserializer()
33
+ elif serde_type == "cachegen":
34
+ s, d = (
35
+ CacheGenSerializer(config, metadata),
36
+ CacheGenDeserializer(config, metadata),
37
+ )
38
+ else:
39
+ raise ValueError(f"Invalid type: {serde_type}")
40
+
41
+ return s, d
42
+
43
+
44
+ __all__ = [
45
+ "Serializer",
46
+ "Deserializer",
47
+ "KIVISerializer",
48
+ "KIVIDeserializer",
49
+ "CreateSerde",
50
+ ]
@@ -0,0 +1,133 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # Standard
3
+ from dataclasses import dataclass
4
+ from typing import List
5
+
6
+ # Third Party
7
+ from transformers import AutoConfig
8
+
9
+ # First Party
10
+ from lmcache.logging import init_logger
11
+ from lmcache.storage_backend.serde.cachegen_basics import QuantizationSpec
12
+
13
+ logger = init_logger(__name__)
14
+
15
+
16
+ @dataclass
17
+ class CacheGenConfig:
18
+ # TODO: move this class to another file like "cachegen_basics.py"
19
+ nlayers: int
20
+ kspecs: List[QuantizationSpec]
21
+ vspecs: List[QuantizationSpec]
22
+
23
+ def __getitem__(self, key: str) -> int:
24
+ return getattr(self, key)
25
+
26
+ @staticmethod
27
+ def from_model_name(model_name: str) -> "CacheGenConfig":
28
+ family_7b = [
29
+ "mistralai/Mistral-7B-Instruct-v0.2",
30
+ "lmsys/longchat-7b-16k",
31
+ "Qwen/Qwen-7B",
32
+ ]
33
+ family_8b = ["meta-llama/Llama-3.1-8B-Instruct"]
34
+ family_9b = ["THUDM/glm-4-9b-chat"]
35
+ if model_name in family_7b:
36
+ return CacheGenConfig(
37
+ nlayers=32,
38
+ kspecs=[
39
+ QuantizationSpec(start_layer=0, end_layer=10, bins=32),
40
+ QuantizationSpec(start_layer=10, end_layer=32, bins=16),
41
+ ],
42
+ vspecs=[
43
+ QuantizationSpec(start_layer=0, end_layer=2, bins=32),
44
+ QuantizationSpec(start_layer=2, end_layer=32, bins=16),
45
+ ],
46
+ )
47
+ elif model_name in family_8b:
48
+ return CacheGenConfig(
49
+ nlayers=32,
50
+ kspecs=[
51
+ QuantizationSpec(start_layer=0, end_layer=10, bins=32),
52
+ QuantizationSpec(start_layer=10, end_layer=32, bins=16),
53
+ ],
54
+ vspecs=[
55
+ QuantizationSpec(start_layer=0, end_layer=2, bins=32),
56
+ QuantizationSpec(start_layer=2, end_layer=32, bins=16),
57
+ ],
58
+ )
59
+ # TODO(Jiayi): needs tuning for better quality
60
+ elif model_name in family_9b:
61
+ return CacheGenConfig(
62
+ nlayers=40,
63
+ kspecs=[
64
+ QuantizationSpec(start_layer=0, end_layer=10, bins=32),
65
+ QuantizationSpec(start_layer=10, end_layer=40, bins=16),
66
+ ],
67
+ vspecs=[
68
+ QuantizationSpec(start_layer=0, end_layer=2, bins=32),
69
+ QuantizationSpec(start_layer=2, end_layer=40, bins=16),
70
+ ],
71
+ )
72
+ elif model_name == "test_model":
73
+ return CacheGenConfig(
74
+ nlayers=32,
75
+ kspecs=[
76
+ QuantizationSpec(start_layer=0, end_layer=10, bins=32),
77
+ QuantizationSpec(start_layer=10, end_layer=32, bins=16),
78
+ ],
79
+ vspecs=[
80
+ QuantizationSpec(start_layer=0, end_layer=2, bins=32),
81
+ QuantizationSpec(start_layer=2, end_layer=32, bins=16),
82
+ ],
83
+ )
84
+ else:
85
+ try:
86
+ config = AutoConfig.from_pretrained(model_name)
87
+ # Default name caught by num_hidden_layers
88
+ if config.num_hidden_layers is None:
89
+ raise ValueError(
90
+ f"num_hidden_layers is None for model {model_name}"
91
+ )
92
+ if config.num_hidden_layers < 10:
93
+ return CacheGenConfig(
94
+ nlayers=config.num_hidden_layers,
95
+ kspecs=[
96
+ QuantizationSpec(
97
+ start_layer=0,
98
+ end_layer=config.num_hidden_layers,
99
+ bins=32,
100
+ ),
101
+ ],
102
+ vspecs=[
103
+ QuantizationSpec(
104
+ start_layer=0,
105
+ end_layer=config.num_hidden_layers,
106
+ bins=32,
107
+ ),
108
+ ],
109
+ )
110
+ else:
111
+ return CacheGenConfig(
112
+ nlayers=config.num_hidden_layers,
113
+ kspecs=[
114
+ QuantizationSpec(start_layer=0, end_layer=10, bins=32),
115
+ QuantizationSpec(
116
+ start_layer=10,
117
+ end_layer=config.num_hidden_layers,
118
+ bins=16,
119
+ ),
120
+ ],
121
+ vspecs=[
122
+ QuantizationSpec(start_layer=0, end_layer=2, bins=32),
123
+ QuantizationSpec(
124
+ start_layer=2,
125
+ end_layer=config.num_hidden_layers,
126
+ bins=16,
127
+ ),
128
+ ],
129
+ )
130
+ except Exception as e:
131
+ raise ValueError(
132
+ f"Model {model_name} not supported by CacheGenConfig"
133
+ ) from e
@@ -0,0 +1,135 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # Standard
3
+ from typing import Optional
4
+
5
+ # Third Party
6
+ import torch
7
+
8
+ # First Party
9
+ from lmcache.logging import init_logger
10
+ from lmcache.storage_backend.serde.cachegen_basics import (
11
+ CacheGenGPUEncoderOutput,
12
+ )
13
+ from lmcache.storage_backend.serde.cachegen_decoder import (
14
+ decode_function_gpu,
15
+ do_dequantize,
16
+ )
17
+ from lmcache.utils import _lmcache_nvtx_annotate
18
+ from lmcache.v1.config import LMCacheEngineConfig
19
+ from lmcache.v1.memory_management import (
20
+ BytesBufferMemoryObj,
21
+ MemoryFormat,
22
+ MemoryObj,
23
+ MemoryObjMetadata,
24
+ TensorMemoryObj,
25
+ )
26
+ from lmcache.v1.metadata import LMCacheMetadata
27
+ from lmcache.v1.storage_backend.naive_serde.cachegen_basics import CacheGenConfig
28
+ from lmcache.v1.storage_backend.naive_serde.serde import Deserializer
29
+
30
+ logger = init_logger(__name__)
31
+
32
+
33
+ class CacheGenDeserializer(Deserializer):
34
+ def __init__(self, config: LMCacheEngineConfig, metadata: LMCacheMetadata):
35
+ self.dtype = metadata.kv_dtype
36
+ self.cachegen_config = CacheGenConfig.from_model_name(metadata.model_name)
37
+ self.chunk_size = config.chunk_size
38
+ self.output_buffer: Optional[torch.Tensor] = None
39
+ self.key_bins = self.make_key_bins(self.cachegen_config)
40
+ self.value_bins = self.make_value_bins(self.cachegen_config)
41
+
42
+ def make_key_bins(self, config: CacheGenConfig) -> torch.Tensor:
43
+ ret = torch.zeros(config.nlayers)
44
+ for spec in config.kspecs:
45
+ ret[spec.start_layer : spec.end_layer] = spec.bins
46
+ return ret.cuda()
47
+
48
+ def make_value_bins(self, config: CacheGenConfig) -> torch.Tensor:
49
+ ret = torch.zeros(config.nlayers)
50
+ for spec in config.vspecs:
51
+ ret[spec.start_layer : spec.end_layer] = spec.bins
52
+ return ret.cuda()
53
+
54
+ def get_output_buffer(self, nlayers: int, nchannels: int, ntokens: int):
55
+ if (
56
+ self.output_buffer is None
57
+ or self.output_buffer.shape[1] != 2 * nlayers * nchannels
58
+ ):
59
+ self.output_buffer = torch.zeros(
60
+ (self.chunk_size, 2 * nlayers * nchannels), dtype=torch.uint8
61
+ ).cuda()
62
+ return self.output_buffer[:ntokens, :]
63
+
64
+ # TODO(Jiayi): A lot of memory copies can be avoided in this function.
65
+ @_lmcache_nvtx_annotate
66
+ def deserialize(self, buffer_memory_obj: BytesBufferMemoryObj) -> MemoryObj:
67
+ encoder_output = CacheGenGPUEncoderOutput.from_bytes(
68
+ buffer_memory_obj.byte_array
69
+ )
70
+
71
+ encoder_output.max_tensors_key = encoder_output.max_tensors_key.cuda()
72
+ encoder_output.max_tensors_value = encoder_output.max_tensors_value.cuda()
73
+
74
+ ntokens = encoder_output.max_tensors_key.shape[1]
75
+ layers_in_key = encoder_output.max_tensors_key.shape[0]
76
+ key, value = decode_function_gpu(
77
+ encoder_output.cdf,
78
+ encoder_output.data_chunks,
79
+ layers_in_key,
80
+ ntokens,
81
+ self.get_output_buffer(
82
+ encoder_output.cdf.shape[0] // 2,
83
+ encoder_output.cdf.shape[1],
84
+ ntokens,
85
+ ),
86
+ )
87
+
88
+ # Temporary fix for #83: change the device of key_bins and value_bins
89
+ # to the device of key and value
90
+ # This requires a long-term fix in the future. Currently,
91
+ # CacheGenGPUEncoderOutput has implicit device in itself.
92
+ # More specifically, if the encoder encodes the tensor on GPU0, the
93
+ # from_bytes will also return a tensor on GPU0
94
+ # We may want to dynamically configure the device based on config and
95
+ # metadata in the future
96
+ if self.key_bins.device != key.device:
97
+ self.key_bins = self.key_bins.to(key.device)
98
+
99
+ if self.value_bins.device != value.device:
100
+ self.value_bins = self.value_bins.cuda()
101
+
102
+ key = do_dequantize(key, self.key_bins, encoder_output.max_tensors_key)
103
+ value = do_dequantize(value, self.value_bins, encoder_output.max_tensors_value)
104
+ """ merge key and value back and reshape """
105
+ nlayers, ntokens, nchannels = key.shape
106
+ blob = torch.stack([key, value]) # [2, nlayers, ntokens, nchannels]
107
+ blob = blob.reshape(
108
+ (
109
+ 2,
110
+ nlayers,
111
+ ntokens,
112
+ encoder_output.num_heads,
113
+ encoder_output.head_size,
114
+ )
115
+ )
116
+
117
+ hidden_dim = blob.shape[-1] * blob.shape[-2]
118
+ kv_chunk = blob.reshape(*blob.shape[:-2], hidden_dim).to(
119
+ self.dtype
120
+ ) # [nlayers, 2, ntokens, num_heads, head_size]
121
+
122
+ memory_obj = TensorMemoryObj(
123
+ raw_data=kv_chunk,
124
+ metadata=MemoryObjMetadata(
125
+ shape=kv_chunk.shape,
126
+ dtype=kv_chunk.dtype,
127
+ address=-1,
128
+ phy_size=kv_chunk.numel() * kv_chunk.element_size(),
129
+ ref_count=-1, # HACK: avoid mis-free
130
+ fmt=MemoryFormat.KV_2LTD,
131
+ ),
132
+ parent_allocator=None,
133
+ )
134
+
135
+ return memory_obj
@@ -0,0 +1,83 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # Third Party
3
+ import torch
4
+
5
+ # First Party
6
+ from lmcache.logging import init_logger
7
+ from lmcache.storage_backend.serde.cachegen_encoder import encode_function
8
+ from lmcache.utils import _lmcache_nvtx_annotate
9
+ from lmcache.v1.config import LMCacheEngineConfig
10
+ from lmcache.v1.memory_management import BytesBufferMemoryObj, MemoryObj
11
+ from lmcache.v1.metadata import LMCacheMetadata
12
+ from lmcache.v1.storage_backend.naive_serde.cachegen_basics import CacheGenConfig
13
+ from lmcache.v1.storage_backend.naive_serde.serde import Serializer
14
+
15
+ logger = init_logger(__name__)
16
+
17
+
18
+ class CacheGenSerializer(Serializer):
19
+ def __init__(self, config: LMCacheEngineConfig, metadata: LMCacheMetadata):
20
+ self.cachegen_config = CacheGenConfig.from_model_name(metadata.model_name)
21
+ self.chunk_size = config.chunk_size
22
+ self.key_bins = self.make_key_bins(self.cachegen_config)
23
+ self.value_bins = self.make_value_bins(self.cachegen_config)
24
+
25
+ self.kv_shape = metadata.kv_shape
26
+
27
+ def make_key_bins(self, config: CacheGenConfig) -> torch.Tensor:
28
+ ret = torch.zeros(config.nlayers)
29
+ for spec in config.kspecs:
30
+ ret[spec.start_layer : spec.end_layer] = spec.bins
31
+ return ret.cuda()
32
+
33
+ def make_value_bins(self, config: CacheGenConfig) -> torch.Tensor:
34
+ ret = torch.zeros(config.nlayers)
35
+ for spec in config.vspecs:
36
+ ret[spec.start_layer : spec.end_layer] = spec.bins
37
+ return ret.cuda()
38
+
39
+ # TODO(Jiayi): A lot of memory copies can be avoided in this function.
40
+ @_lmcache_nvtx_annotate
41
+ def serialize(self, memory_obj: MemoryObj) -> BytesBufferMemoryObj:
42
+ """
43
+ Serialize a KV_2LTD MemoryObj to CACHEGEN_BINARY MemoryObj.
44
+
45
+ Input:
46
+ memory_obj: the memory object to be serialized.
47
+
48
+ Returns:
49
+ MemoryObj: the serialized binary memory object.
50
+ """
51
+
52
+ # TODO(Jiayi): please avoid this copy by directly performing
53
+ # serialization inside gpu connector.
54
+ assert memory_obj.tensor is not None
55
+ tensor = memory_obj.tensor.cuda()
56
+
57
+ # Temporary fix for issue #83: encoder will have the default device 0
58
+ # on all the ray workers. Need to set it to the correct device.
59
+ # Also need to figure out why this happens.
60
+ if torch.cuda.current_device != tensor.device:
61
+ torch.cuda.set_device(tensor.device)
62
+ if tensor.device != self.key_bins.device:
63
+ self.key_bins = self.key_bins.to(tensor.device)
64
+ if tensor.device != self.value_bins.device:
65
+ self.value_bins = self.value_bins.to(tensor.device)
66
+
67
+ # tensor is [2, num_layers, num_tokens, hidden_size]
68
+ tensor = tensor.view(*tensor.shape[:-1], self.kv_shape[-2], self.kv_shape[-1])
69
+ tensor = tensor.permute([1, 0, 2, 3, 4])
70
+
71
+ # TODO(Jiayi): remove hardcoded "2"
72
+ """ expecting a tensor of shape
73
+ [num_layers, 2, num_tokens, num_heads, head_size] """
74
+ ntokens = tensor.shape[2]
75
+ output_dict = encode_function(
76
+ tensor,
77
+ self.cachegen_config,
78
+ self.key_bins,
79
+ self.value_bins,
80
+ ntokens,
81
+ )
82
+
83
+ return BytesBufferMemoryObj(output_dict.to_bytes())
@@ -0,0 +1,22 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # First Party
3
+ from lmcache.v1.memory_management import MemoryObj
4
+ from lmcache.v1.storage_backend.naive_serde.serde import Deserializer, Serializer
5
+
6
+
7
+ class KIVISerializer(Serializer):
8
+ def __init__(self):
9
+ pass
10
+
11
+ def serialize(self, memory_obj: MemoryObj) -> MemoryObj:
12
+ # TODO(Yuhan)
13
+ return memory_obj
14
+
15
+
16
+ class KIVIDeserializer(Deserializer):
17
+ def __init__(self):
18
+ pass
19
+
20
+ def deserialize(self, memory_obj: MemoryObj) -> MemoryObj:
21
+ # TODO(Yuhan)
22
+ return memory_obj
@@ -0,0 +1,18 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # First Party
3
+ from lmcache.v1.memory_management import MemoryObj
4
+ from lmcache.v1.storage_backend.naive_serde.serde import Deserializer, Serializer
5
+
6
+
7
+ class NaiveSerializer(Serializer):
8
+ def __init__(self):
9
+ pass
10
+
11
+ def serialize(self, memory_obj: MemoryObj) -> MemoryObj:
12
+ memory_obj.ref_count_up()
13
+ return memory_obj
14
+
15
+
16
+ class NaiveDeserializer(Deserializer):
17
+ def deserialize(self, memory_obj: MemoryObj) -> MemoryObj:
18
+ return memory_obj
@@ -0,0 +1,37 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # Standard
3
+ import abc
4
+
5
+ # First Party
6
+ from lmcache.v1.memory_management import MemoryObj
7
+
8
+
9
+ class Serializer(metaclass=abc.ABCMeta):
10
+ @abc.abstractmethod
11
+ def serialize(self, memory_obj: MemoryObj) -> MemoryObj:
12
+ """
13
+ Serialize/compress the memory object.
14
+
15
+ Input:
16
+ memory_obj: the memory object to be serialized/compressed.
17
+
18
+ Returns:
19
+ MemoryObj: the serialized/compressed memory object.
20
+ """
21
+ raise NotImplementedError
22
+
23
+
24
+ class Deserializer(metaclass=abc.ABCMeta):
25
+ @abc.abstractmethod
26
+ def deserialize(self, memory_obj: MemoryObj) -> MemoryObj:
27
+ """
28
+ Deserialize/decompress the memory object.
29
+
30
+ Input:
31
+ memory_obj: the memory object to be deserialized/decompressed.
32
+
33
+ Returns:
34
+ MemoryObj: the deserialized/decompressed memory object.
35
+ None: if the memory allocation fails.
36
+ """
37
+ raise NotImplementedError
@@ -0,0 +1,165 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # Standard
3
+ from typing import Any, Dict, Generic, Optional, Tuple, TypeVar, Union
4
+ import asyncio
5
+ import concurrent.futures
6
+
7
+ NativeClientT = TypeVar("NativeClientT")
8
+
9
+
10
+ class ConnectorClientBase(Generic[NativeClientT]):
11
+ def __init__(
12
+ self,
13
+ native_client: NativeClientT,
14
+ loop: Optional[asyncio.AbstractEventLoop] = None,
15
+ ):
16
+ self.loop = loop or asyncio.get_running_loop()
17
+ self._client: NativeClientT = native_client
18
+ self._fd = int(self._client.event_fd()) # type: ignore[attr-defined]
19
+ self._closed = False
20
+ # Keepalive refs prevent buffers passed to native code from being
21
+ # garbage-collected while C++ worker threads still hold raw pointers.
22
+ self._pending: Dict[
23
+ int,
24
+ Tuple[
25
+ Union[asyncio.Future, concurrent.futures.Future], str, Tuple[Any, ...]
26
+ ],
27
+ ] = {}
28
+ self.loop.add_reader(self._fd, self._on_ready)
29
+
30
+ def _on_ready(self) -> None:
31
+ if self._closed:
32
+ return
33
+
34
+ try:
35
+ while True:
36
+ items = self._client.drain_completions() # type: ignore[attr-defined]
37
+ if not items:
38
+ return
39
+
40
+ for future_id, ok, error, result_bools in items:
41
+ fid = int(future_id)
42
+ entry = self._pending.pop(fid, None)
43
+ if entry is None:
44
+ continue
45
+
46
+ fut, op, _keepalive = entry
47
+ if fut.done():
48
+ continue
49
+
50
+ if ok:
51
+ if op == "exists":
52
+ if result_bools is not None and len(result_bools) > 0:
53
+ fut.set_result(bool(result_bools[0]))
54
+ else:
55
+ fut.set_result(False)
56
+ elif op == "batch_exists":
57
+ if result_bools is not None:
58
+ fut.set_result(list(result_bools))
59
+ else:
60
+ fut.set_result([])
61
+ else:
62
+ fut.set_result(None)
63
+ else:
64
+ fut.set_exception(RuntimeError(str(error)))
65
+ except Exception as e:
66
+ self._fail_all(RuntimeError(f"native drain_completions failed: {e}"))
67
+ self._shutdown_native(best_effort=True)
68
+
69
+ def _fail_all(self, exc: Exception) -> None:
70
+ for fid, (fut, _, _keepalive) in list(self._pending.items()):
71
+ if not fut.done():
72
+ fut.set_exception(exc)
73
+ self._pending.clear()
74
+
75
+ def _shutdown_native(self, best_effort: bool = False) -> None:
76
+ try:
77
+ self._closed = True
78
+ self.loop.remove_reader(self._fd)
79
+ except Exception:
80
+ if not best_effort:
81
+ raise
82
+
83
+ def _register_future_async(
84
+ self, op: str, future_id: int, keepalive: Tuple[Any, ...] = ()
85
+ ) -> asyncio.Future:
86
+ fut = self.loop.create_future()
87
+ self._pending[int(future_id)] = (fut, op, keepalive)
88
+ return fut
89
+
90
+ def _register_future_sync(
91
+ self, op: str, future_id: int, keepalive: Tuple[Any, ...] = ()
92
+ ) -> concurrent.futures.Future:
93
+ fut: concurrent.futures.Future = concurrent.futures.Future()
94
+ self._pending[int(future_id)] = (fut, op, keepalive)
95
+ return fut
96
+
97
+ async def get(self, key: str, buf: memoryview) -> None:
98
+ return await self.batch_get([key], [buf])
99
+
100
+ async def set(self, key: str, buf: memoryview) -> None:
101
+ return await self.batch_set([key], [buf])
102
+
103
+ async def exists(self, key: str) -> bool:
104
+ results = await self.batch_exists([key])
105
+ return results[0]
106
+
107
+ async def batch_get(self, keys: list[str], bufs: list[memoryview]) -> None:
108
+ if len(keys) != len(bufs):
109
+ raise ValueError("keys and bufs length mismatch")
110
+ future_id = int(self._client.submit_batch_get(keys, bufs)) # type: ignore[attr-defined]
111
+ fut = self._register_future_async("batch_get", future_id, (keys, tuple(bufs)))
112
+ return await fut
113
+
114
+ async def batch_set(self, keys: list[str], bufs: list[memoryview]) -> None:
115
+ if len(keys) != len(bufs):
116
+ raise ValueError("keys and bufs length mismatch")
117
+ future_id = int(self._client.submit_batch_set(keys, bufs)) # type: ignore[attr-defined]
118
+ fut = self._register_future_async("batch_set", future_id, (keys, tuple(bufs)))
119
+ return await fut
120
+
121
+ async def batch_exists(self, keys: list[str]) -> list[bool]:
122
+ future_id = int(self._client.submit_batch_exists(keys)) # type: ignore[attr-defined]
123
+ fut = self._register_future_async("batch_exists", future_id)
124
+ return await fut
125
+
126
+ async def batched_exists(self, keys: list[str]) -> list[bool]:
127
+ return await self.batch_exists(keys)
128
+
129
+ def get_sync(self, key: str, buf: memoryview) -> None:
130
+ return self.batch_get_sync([key], [buf])
131
+
132
+ def set_sync(self, key: str, buf: memoryview) -> None:
133
+ return self.batch_set_sync([key], [buf])
134
+
135
+ def exists_sync(self, key: str) -> bool:
136
+ results = self.batch_exists_sync([key])
137
+ return results[0]
138
+
139
+ def batch_get_sync(self, keys: list[str], bufs: list[memoryview]) -> None:
140
+ if len(keys) != len(bufs):
141
+ raise ValueError("keys and bufs length mismatch")
142
+ future_id = int(self._client.submit_batch_get(keys, bufs)) # type: ignore[attr-defined]
143
+ fut = self._register_future_sync("batch_get", future_id, (keys, tuple(bufs)))
144
+ return fut.result()
145
+
146
+ def batch_set_sync(self, keys: list[str], bufs: list[memoryview]) -> None:
147
+ if len(keys) != len(bufs):
148
+ raise ValueError("keys and bufs length mismatch")
149
+ future_id = int(self._client.submit_batch_set(keys, bufs)) # type: ignore[attr-defined]
150
+ fut = self._register_future_sync("batch_set", future_id, (keys, tuple(bufs)))
151
+ return fut.result()
152
+
153
+ def batch_exists_sync(self, keys: list[str]) -> list[bool]:
154
+ future_id = int(self._client.submit_batch_exists(keys)) # type: ignore[attr-defined]
155
+ fut = self._register_future_sync("batch_exists", future_id)
156
+ return fut.result()
157
+
158
+ def batched_exists_sync(self, keys: list[str]) -> list[bool]:
159
+ return self.batch_exists_sync(keys)
160
+
161
+ def close(self) -> None:
162
+ if not self._closed:
163
+ self._shutdown_native(best_effort=True)
164
+ self._fail_all(RuntimeError("Client closed"))
165
+ self._client.close() # type: ignore[attr-defined]
@@ -0,0 +1,35 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # Standard
3
+ from typing import Optional
4
+ import asyncio
5
+
6
+ # Local
7
+ from .connector_client_base import ConnectorClientBase
8
+
9
+ try:
10
+ # First Party
11
+ from lmcache.lmcache_redis import LMCacheRedisClient
12
+
13
+ REDIS_AVAILABLE = True
14
+ except ImportError:
15
+ REDIS_AVAILABLE = False
16
+ LMCacheRedisClient = None # type: ignore
17
+
18
+
19
+ class RESPClient(ConnectorClientBase[LMCacheRedisClient]):
20
+ def __init__(
21
+ self,
22
+ host: str,
23
+ port: int,
24
+ num_workers: int,
25
+ loop: Optional[asyncio.AbstractEventLoop] = None,
26
+ username: str = "",
27
+ password: str = "",
28
+ ):
29
+ if not REDIS_AVAILABLE:
30
+ raise RuntimeError(
31
+ "RESPClient requires the C++ Redis extension. "
32
+ "Build with: pip install -e ."
33
+ )
34
+ native_client = LMCacheRedisClient(host, port, num_workers, username, password)
35
+ super().__init__(native_client, loop)