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,660 @@
1
+ // Controller Dashboard JavaScript
2
+ // Global variables
3
+ let controllerBaseUrl = "";
4
+ let isConnected = false;
5
+ let currentInstances = [];
6
+ let currentWorkers = [];
7
+ let currentKeyPool = [];
8
+ let envVariablesData = null;
9
+
10
+ // Initialize after DOM is loaded
11
+ window.addEventListener('DOMContentLoaded', () => {
12
+ // Initialize current time display
13
+ updateCurrentTime();
14
+ setInterval(updateCurrentTime, 1000);
15
+
16
+ // Connect button event
17
+ document.getElementById('connectControllerBtn').addEventListener('click', connectToController);
18
+
19
+ // Refresh all button
20
+ document.getElementById('refreshAllBtn').addEventListener('click', refreshAllData);
21
+
22
+ // Tab switching event
23
+ document.querySelectorAll('.nav-link').forEach(tab => {
24
+ tab.addEventListener('shown.bs.tab', (event) => {
25
+ if (isConnected) {
26
+ const tabId = event.target.getAttribute('data-bs-target').replace('#', '');
27
+ loadTabData(tabId);
28
+ }
29
+ });
30
+ });
31
+
32
+ // Instance management
33
+ document.getElementById('refreshInstancesBtn').addEventListener('click', loadInstances);
34
+ document.getElementById('saveInstanceBtn').addEventListener('click', addInstance);
35
+
36
+ // Worker management
37
+ document.getElementById('refreshWorkersBtn').addEventListener('click', loadWorkers);
38
+ document.getElementById('instanceFilter').addEventListener('change', loadWorkers);
39
+
40
+ // Metrics
41
+ document.getElementById('refreshMetricsBtn').addEventListener('click', loadMetrics);
42
+
43
+ // Threads
44
+ document.getElementById('refreshThreadsBtn').addEventListener('click', loadThreads);
45
+
46
+ // Environment
47
+ document.getElementById('envSearchInput').addEventListener('input', filterEnvVariables);
48
+
49
+ // Auto-connect on startup
50
+ const urlParams = new URLSearchParams(window.location.search);
51
+ const urlHostParam = urlParams.get('host');
52
+ const urlPortParam = urlParams.get('port');
53
+
54
+ // Get host and port from URL parameters, or use current page's hostname and port
55
+ const autoHost = urlHostParam || window.location.hostname;
56
+ const autoPort = urlPortParam || window.location.port || (window.location.protocol === 'https:' ? '443' : '80');
57
+
58
+ // Always set input values and attempt to connect
59
+ document.getElementById('controllerHostInput').value = autoHost;
60
+ document.getElementById('controllerPortInput').value = autoPort;
61
+ setTimeout(() => connectToController(), 1000);
62
+ });
63
+
64
+ // Update current time display
65
+ function updateCurrentTime() {
66
+ const now = new Date();
67
+ const timeString = now.toLocaleTimeString('en-US', {
68
+ hour12: false,
69
+ hour: '2-digit',
70
+ minute: '2-digit',
71
+ second: '2-digit'
72
+ });
73
+ document.getElementById('currentTime').textContent = timeString;
74
+ }
75
+
76
+ // Connect to Controller
77
+ async function connectToController() {
78
+ const host = document.getElementById('controllerHostInput').value.trim();
79
+ const port = document.getElementById('controllerPortInput').value.trim();
80
+
81
+ if (!host || !port) {
82
+ alert('Please enter controller host and port');
83
+ return;
84
+ }
85
+
86
+ // Construct the base URL
87
+ const protocol = window.location.protocol;
88
+ controllerBaseUrl = `${protocol}//${host}:${port}`;
89
+ const statusElement = document.getElementById('connectionStatus');
90
+
91
+ try {
92
+ statusElement.textContent = 'Connecting...';
93
+ statusElement.className = 'badge bg-warning';
94
+
95
+ // Test connection with a simple health check
96
+ const response = await fetch(`${controllerBaseUrl}/health`, {
97
+ method: 'POST',
98
+ headers: {'Content-Type': 'application/json'},
99
+ body: JSON.stringify({ instance_id: 'test' })
100
+ });
101
+
102
+ if (response.ok) {
103
+ isConnected = true;
104
+ statusElement.textContent = 'Connected';
105
+ statusElement.className = 'badge bg-success';
106
+
107
+ // Load initial data
108
+ loadOverview();
109
+ loadInstances();
110
+ loadWorkers();
111
+
112
+ // Update URL with connection parameters
113
+ const newUrl = new URL(window.location);
114
+ newUrl.searchParams.set('host', host);
115
+ newUrl.searchParams.set('port', port);
116
+ window.history.replaceState({}, '', newUrl);
117
+
118
+ } else {
119
+ throw new Error('Connection failed');
120
+ }
121
+ } catch (error) {
122
+ console.error('Connection error:', error);
123
+ statusElement.textContent = 'Connection Failed';
124
+ statusElement.className = 'badge bg-danger';
125
+ isConnected = false;
126
+ alert('Failed to connect to controller: ' + error.message);
127
+ }
128
+ }
129
+
130
+ // Refresh all data
131
+ async function refreshAllData() {
132
+ if (!isConnected) {
133
+ alert('Please connect to controller first');
134
+ return;
135
+ }
136
+
137
+ const activeTab = document.querySelector('.tab-pane.active').id;
138
+ loadTabData(activeTab);
139
+ }
140
+
141
+ // Load data for active tab
142
+ function loadTabData(tabId) {
143
+ if (!isConnected) return;
144
+
145
+ switch (tabId) {
146
+ case 'overview':
147
+ loadOverview();
148
+ break;
149
+ case 'instances':
150
+ loadInstances();
151
+ break;
152
+ case 'workers':
153
+ loadWorkers();
154
+ break;
155
+ case 'metrics':
156
+ loadMetrics();
157
+ break;
158
+ case 'threads':
159
+ loadThreads();
160
+ break;
161
+ case 'env':
162
+ loadEnvironment();
163
+ break;
164
+ }
165
+ }
166
+
167
+ // Load overview data
168
+ async function loadOverview() {
169
+ if (!isConnected) return;
170
+
171
+ const systemStatusElement = document.getElementById('systemStatus');
172
+ const quickStatsElement = document.getElementById('quickStats');
173
+ const recentActivitiesElement = document.getElementById('recentActivities');
174
+
175
+ try {
176
+ // Load system status
177
+ const healthResponse = await fetch(`${controllerBaseUrl}/health`, {
178
+ method: 'POST',
179
+ headers: {'Content-Type': 'application/json'},
180
+ body: JSON.stringify({ instance_id: 'system' })
181
+ });
182
+
183
+ if (healthResponse.ok) {
184
+ const healthData = await healthResponse.json();
185
+ systemStatusElement.innerHTML = `
186
+ <div class="text-success">
187
+ <i class="bi bi-check-circle-fill fs-1"></i>
188
+ <p class="mt-2">Controller is running</p>
189
+ <small class="text-muted">Event ID: ${healthData.event_id}</small>
190
+ </div>
191
+ `;
192
+ }
193
+
194
+ // Load quick stats (instance count, worker count, key count)
195
+ const response = await fetch(`${controllerBaseUrl}/query_worker_info`, {
196
+ method: 'POST',
197
+ headers: {'Content-Type': 'application/json'},
198
+ body: JSON.stringify({ instance_id: 'all', worker_ids: [] })
199
+ });
200
+
201
+ // Load key stats
202
+ const keyStatsResponse = await fetch(`${controllerBaseUrl}/controller/key-stats`, {
203
+ method: 'GET',
204
+ headers: {'Content-Type': 'application/json'}
205
+ });
206
+
207
+ if (response.ok && keyStatsResponse.ok) {
208
+ const data = await response.json();
209
+ const keyStatsData = await keyStatsResponse.json();
210
+ const instanceCount = new Set(data.worker_infos.map(w => w.instance_id)).size;
211
+ const workerCount = data.worker_infos.length;
212
+ const keyCount = keyStatsData.total_key_count;
213
+
214
+ quickStatsElement.innerHTML = `
215
+ <div class="row">
216
+ <div class="col-4">
217
+ <div class="card bg-light mb-2">
218
+ <div class="card-body p-2">
219
+ <h6 class="card-title mb-0">Instances</h6>
220
+ <h3 class="mb-0">${instanceCount}</h3>
221
+ </div>
222
+ </div>
223
+ </div>
224
+ <div class="col-4">
225
+ <div class="card bg-light mb-2">
226
+ <div class="card-body p-2">
227
+ <h6 class="card-title mb-0">Workers</h6>
228
+ <h3 class="mb-0">${workerCount}</h3>
229
+ </div>
230
+ </div>
231
+ </div>
232
+ <div class="col-4">
233
+ <div class="card bg-light mb-2">
234
+ <div class="card-body p-2">
235
+ <h6 class="card-title mb-0">Total Keys</h6>
236
+ <h3 class="mb-0">${keyCount}</h3>
237
+ </div>
238
+ </div>
239
+ </div>
240
+ </div>
241
+ `;
242
+ }
243
+
244
+ // Recent activities (placeholder)
245
+ recentActivitiesElement.innerHTML = `
246
+ <div class="list-group">
247
+ <div class="list-group-item">
248
+ <small class="text-muted">Just now</small>
249
+ <p class="mb-1">Controller dashboard loaded</p>
250
+ </div>
251
+ <div class="list-group-item">
252
+ <small class="text-muted">2 minutes ago</small>
253
+ <p class="mb-1">Health check performed</p>
254
+ </div>
255
+ </div>
256
+ `;
257
+
258
+ } catch (error) {
259
+ console.error('Error loading overview:', error);
260
+ systemStatusElement.innerHTML = `<div class="alert alert-danger">Error: ${error.message}</div>`;
261
+ }
262
+ }
263
+
264
+ // Load instances
265
+ async function loadInstances() {
266
+ if (!isConnected) return;
267
+
268
+ const tableBody = document.getElementById('instancesTableBody');
269
+ tableBody.innerHTML = '<tr><td colspan="7" class="text-center"><div class="spinner-border" role="status"></div></td></tr>';
270
+
271
+ try {
272
+ const response = await fetch(`${controllerBaseUrl}/query_worker_info`, {
273
+ method: 'POST',
274
+ headers: {'Content-Type': 'application/json'},
275
+ body: JSON.stringify({ instance_id: 'all' })
276
+ });
277
+
278
+ // Load key stats for instances
279
+ const keyStatsResponse = await fetch(`${controllerBaseUrl}/controller/key-stats`, {
280
+ method: 'GET',
281
+ headers: {'Content-Type': 'application/json'}
282
+ });
283
+
284
+ if (!response.ok || !keyStatsResponse.ok) {
285
+ throw new Error('Failed to fetch instances or key stats');
286
+ }
287
+
288
+ const data = await response.json();
289
+ const keyStatsData = await keyStatsResponse.json();
290
+ currentInstances = data.worker_infos;
291
+
292
+ // Create a map of instance key counts from key stats
293
+ const instanceKeyCounts = new Map();
294
+ keyStatsData.instances.forEach(instance => {
295
+ instanceKeyCounts.set(instance.instance_id, instance.key_count);
296
+ });
297
+
298
+ // Group workers by instance
299
+ const instancesMap = new Map();
300
+ currentInstances.forEach(worker => {
301
+ if (!instancesMap.has(worker.instance_id)) {
302
+ instancesMap.set(worker.instance_id, {
303
+ instance_id: worker.instance_id,
304
+ ip: worker.ip,
305
+ workers: [],
306
+ last_heartbeat: worker.last_heartbeat_time,
307
+ key_count: instanceKeyCounts.get(worker.instance_id) || 0
308
+ });
309
+ }
310
+ instancesMap.get(worker.instance_id).workers.push(worker);
311
+ // Update latest heartbeat
312
+ if (worker.last_heartbeat_time > instancesMap.get(worker.instance_id).last_heartbeat) {
313
+ instancesMap.get(worker.instance_id).last_heartbeat = worker.last_heartbeat_time;
314
+ }
315
+ });
316
+
317
+ // Update instance filter dropdown
318
+ const instanceFilter = document.getElementById('instanceFilter');
319
+ instanceFilter.innerHTML = '<option value="">All Instances</option>';
320
+ instancesMap.forEach((instance, instanceId) => {
321
+ const option = document.createElement('option');
322
+ option.value = instanceId;
323
+ option.textContent = instanceId;
324
+ instanceFilter.appendChild(option);
325
+ });
326
+
327
+ // Update HTML table header to include Key Count column
328
+ const tableHeader = document.querySelector('#instances thead tr');
329
+ if (tableHeader && !tableHeader.innerHTML.includes('Key Count')) {
330
+ tableHeader.innerHTML = `
331
+ <th>Instance ID</th>
332
+ <th>IP Address</th>
333
+ <th>Status</th>
334
+ <th>Worker Count</th>
335
+ <th>Key Count</th>
336
+ <th>Last Heartbeat</th>
337
+ <th>Actions</th>
338
+ `;
339
+ }
340
+
341
+ // Populate table
342
+ tableBody.innerHTML = '';
343
+ instancesMap.forEach((instance, instanceId) => {
344
+ const row = document.createElement('tr');
345
+ const now = Math.floor(Date.now() / 1000);
346
+ const timeDiff = now - instance.last_heartbeat;
347
+ const status = timeDiff < 60 ? 'Active' : timeDiff < 300 ? 'Warning' : 'Inactive';
348
+ const statusClass = timeDiff < 60 ? 'status-active' : timeDiff < 300 ? 'status-warning' : 'status-inactive';
349
+
350
+ const lastHeartbeat = new Date(instance.last_heartbeat * 1000).toLocaleTimeString();
351
+
352
+ row.innerHTML = `
353
+ <td><strong>${instanceId}</strong></td>
354
+ <td>${instance.ip}</td>
355
+ <td><span class="${statusClass}">${status}</span></td>
356
+ <td>${instance.workers.length}</td>
357
+ <td>${instance.key_count}</td>
358
+ <td>${lastHeartbeat}</td>
359
+ <td>
360
+ <button class="btn btn-sm btn-info view-instance" data-instance="${instanceId}">View</button>
361
+ <button class="btn btn-sm btn-danger remove-instance" data-instance="${instanceId}">Remove</button>
362
+ </td>
363
+ `;
364
+ tableBody.appendChild(row);
365
+ });
366
+
367
+ // Add event listeners to buttons
368
+ document.querySelectorAll('.view-instance').forEach(btn => {
369
+ btn.addEventListener('click', (e) => {
370
+ const instanceId = e.target.dataset.instance;
371
+ alert(`Viewing instance: ${instanceId}`);
372
+ // In a real implementation, this would navigate to instance details
373
+ });
374
+ });
375
+
376
+ document.querySelectorAll('.remove-instance').forEach(btn => {
377
+ btn.addEventListener('click', (e) => {
378
+ const instanceId = e.target.dataset.instance;
379
+ if (confirm(`Are you sure you want to remove instance ${instanceId}?`)) {
380
+ removeInstance(instanceId);
381
+ }
382
+ });
383
+ });
384
+
385
+ } catch (error) {
386
+ console.error('Error loading instances:', error);
387
+ tableBody.innerHTML = `<tr><td colspan="7" class="text-center text-danger">Error: ${error.message}</td></tr>`;
388
+ }
389
+ }
390
+
391
+ // Add instance (placeholder - would need backend implementation)
392
+ async function addInstance() {
393
+ const instanceId = document.getElementById('newInstanceId').value.trim();
394
+ const instanceIp = document.getElementById('newInstanceIp').value.trim();
395
+
396
+ if (!instanceId || !instanceIp) {
397
+ alert('Please fill all fields');
398
+ return;
399
+ }
400
+
401
+ // This is a placeholder - in reality, you would need a backend endpoint to add instances
402
+ alert(`Would add instance: ${instanceId} with IP: ${instanceIp}`);
403
+
404
+ // Close modal
405
+ const modal = bootstrap.Modal.getInstance(document.getElementById('addInstanceModal'));
406
+ modal.hide();
407
+
408
+ // Clear form
409
+ document.getElementById('newInstanceId').value = '';
410
+ document.getElementById('newInstanceIp').value = '';
411
+
412
+ // Refresh instances list
413
+ loadInstances();
414
+ }
415
+
416
+ // Remove instance (placeholder)
417
+ async function removeInstance(instanceId) {
418
+ // This is a placeholder - in reality, you would need a backend endpoint to remove instances
419
+ alert(`Would remove instance: ${instanceId}`);
420
+ loadInstances();
421
+ }
422
+
423
+ // Load workers
424
+ async function loadWorkers() {
425
+ if (!isConnected) return;
426
+
427
+ const tableBody = document.getElementById('workersTableBody');
428
+ const instanceFilter = document.getElementById('instanceFilter').value;
429
+
430
+ tableBody.innerHTML = '<tr><td colspan="8" class="text-center"><div class="spinner-border" role="status"></div></td></tr>';
431
+
432
+ try {
433
+ const requestBody = instanceFilter ?
434
+ { instance_id: instanceFilter, worker_ids: [] } :
435
+ { instance_id: 'all', worker_ids: [] };
436
+
437
+ const response = await fetch(`${controllerBaseUrl}/query_worker_info`, {
438
+ method: 'POST',
439
+ headers: {'Content-Type': 'application/json'},
440
+ body: JSON.stringify(requestBody)
441
+ });
442
+
443
+ if (!response.ok) {
444
+ throw new Error('Failed to fetch workers');
445
+ }
446
+
447
+ const data = await response.json();
448
+ currentWorkers = data.worker_infos;
449
+
450
+ // Get detailed worker info with key counts
451
+ const workersWithKeyCounts = await Promise.all(
452
+ currentWorkers.map(async (worker) => {
453
+ try {
454
+ // Get detailed worker info including key count
455
+ const workerDetailResponse = await fetch(`${controllerBaseUrl}/controller/workers?instance_id=${worker.instance_id}&worker_id=${worker.worker_id}`, {
456
+ method: 'GET',
457
+ headers: {'Content-Type': 'application/json'}
458
+ });
459
+
460
+ if (workerDetailResponse.ok) {
461
+ const workerDetail = await workerDetailResponse.json();
462
+ return {
463
+ ...worker,
464
+ key_count: workerDetail.key_count || 0
465
+ };
466
+ }
467
+ } catch (error) {
468
+ console.warn(`Failed to get key count for worker ${worker.instance_id}/${worker.worker_id}:`, error);
469
+ }
470
+
471
+ // Fallback to 0 if key count is not available
472
+ return {
473
+ ...worker,
474
+ key_count: 0
475
+ };
476
+ })
477
+ );
478
+
479
+ // Update HTML table header to include Key Count column
480
+ const tableHeader = document.querySelector('#workers thead tr');
481
+ if (tableHeader && !tableHeader.innerHTML.includes('Key Count')) {
482
+ tableHeader.innerHTML = `
483
+ <th>Instance ID</th>
484
+ <th>Worker ID</th>
485
+ <th>IP</th>
486
+ <th>Port</th>
487
+ <th>Status</th>
488
+ <th>Key Count</th>
489
+ <th>Last Heartbeat</th>
490
+ <th>Actions</th>
491
+ `;
492
+ }
493
+
494
+ // Populate table
495
+ tableBody.innerHTML = '';
496
+ workersWithKeyCounts.forEach(worker => {
497
+ const row = document.createElement('tr');
498
+ const now = Math.floor(Date.now() / 1000);
499
+ const timeDiff = now - worker.last_heartbeat_time;
500
+ const status = timeDiff < 60 ? 'Active' : timeDiff < 300 ? 'Warning' : 'Inactive';
501
+ const statusClass = timeDiff < 60 ? 'status-active' : timeDiff < 300 ? 'status-warning' : 'status-inactive';
502
+
503
+ const lastHeartbeat = new Date(worker.last_heartbeat_time * 1000).toLocaleTimeString();
504
+
505
+ row.innerHTML = `
506
+ <td>${worker.instance_id}</td>
507
+ <td>${worker.worker_id}</td>
508
+ <td>${worker.ip}</td>
509
+ <td>${worker.port}</td>
510
+ <td><span class="${statusClass}">${status}</span></td>
511
+ <td>${worker.key_count}</td>
512
+ <td>${lastHeartbeat}</td>
513
+ <td>
514
+ <button class="btn btn-sm btn-info view-worker" data-instance="${worker.instance_id}" data-worker="${worker.worker_id}">View</button>
515
+ </td>
516
+ `;
517
+ tableBody.appendChild(row);
518
+ });
519
+
520
+ } catch (error) {
521
+ console.error('Error loading workers:', error);
522
+ tableBody.innerHTML = `<tr><td colspan="8" class="text-center text-danger">Error: ${error.message}</td></tr>`;
523
+ }
524
+ }
525
+
526
+ // Load log level
527
+ async function removeKey(key) {
528
+ // This is a placeholder - in reality, you would need a backend endpoint to remove keys
529
+ alert(`Would remove key: ${key}`);
530
+ loadKeyPool();
531
+ }
532
+
533
+ // Load metrics
534
+ async function loadMetrics() {
535
+ if (!isConnected) return;
536
+
537
+ const contentDiv = document.getElementById('metricsContent');
538
+ contentDiv.textContent = 'Loading...';
539
+
540
+ try {
541
+ // Note: This endpoint might not exist in the current controller
542
+ // You would need to implement a metrics endpoint
543
+ const response = await fetch(`${controllerBaseUrl}/metrics`);
544
+
545
+ if (response.ok) {
546
+ const metrics = await response.text();
547
+ contentDiv.textContent = metrics;
548
+ } else {
549
+ contentDiv.textContent = 'Metrics endpoint not available. Would need to implement /metrics endpoint.';
550
+ }
551
+ } catch (error) {
552
+ contentDiv.textContent = `Failed to load metrics: ${error.message}`;
553
+ }
554
+ }
555
+
556
+ // Load environment variables
557
+ async function loadEnvironment() {
558
+ if (!isConnected) return;
559
+
560
+ const contentDiv = document.getElementById('envContent');
561
+ const searchInput = document.getElementById('envSearchInput');
562
+ contentDiv.textContent = 'Loading...';
563
+ searchInput.value = '';
564
+
565
+ try {
566
+ // Call /env API to get environment variables
567
+ const response = await fetch(`${controllerBaseUrl}/env`);
568
+
569
+ if (!response.ok) {
570
+ throw new Error('Failed to fetch environment variables');
571
+ }
572
+
573
+ envVariablesData = await response.json();
574
+
575
+ // Format for display
576
+ if (typeof envVariablesData === 'object' && envVariablesData !== null) {
577
+ const formattedText = Object.entries(envVariablesData)
578
+ .map(([key, value]) => `${key}=${value}`)
579
+ .join('\n');
580
+ contentDiv.textContent = formattedText;
581
+ } else {
582
+ contentDiv.textContent = 'No environment variables found or invalid data format';
583
+ envVariablesData = null;
584
+ }
585
+ } catch (error) {
586
+ console.error('Error loading environment variables:', error);
587
+ contentDiv.textContent = `Failed to load environment variables: ${error.message}`;
588
+ envVariablesData = null;
589
+ }
590
+ }
591
+
592
+ // Filter environment variables
593
+ function filterEnvVariables() {
594
+ const searchInput = document.getElementById('envSearchInput');
595
+ const contentDiv = document.getElementById('envContent');
596
+ const searchTerm = searchInput.value.toLowerCase();
597
+
598
+ if (!envVariablesData) return;
599
+
600
+ if (typeof envVariablesData === 'object') {
601
+ const filteredEntries = Object.entries(envVariablesData).filter(([key, value]) => {
602
+ const line = `${key}=${value}`;
603
+ return line.toLowerCase().includes(searchTerm);
604
+ });
605
+ const formattedText = filteredEntries
606
+ .map(([key, value]) => `${key}=${value}`)
607
+ .join('\n');
608
+ contentDiv.textContent = formattedText;
609
+ }
610
+ }
611
+
612
+ // Load threads
613
+ async function loadThreads() {
614
+ if (!isConnected) return;
615
+
616
+ const contentDiv = document.getElementById('threadsContent');
617
+ contentDiv.textContent = 'Loading...';
618
+
619
+ try {
620
+ const response = await fetch(`${controllerBaseUrl}/threads`);
621
+
622
+ if (!response.ok) {
623
+ throw new Error('Failed to fetch threads');
624
+ }
625
+
626
+ // Try to parse as JSON first
627
+ const responseText = await response.text();
628
+
629
+ let formattedText;
630
+ try {
631
+ // Try to parse as JSON
632
+ const threadsData = JSON.parse(responseText);
633
+
634
+ // Format threads data as text
635
+ formattedText = '';
636
+ threadsData.forEach((thread, index) => {
637
+ formattedText += `Thread: ${thread.function_name}\n`;
638
+ // Add thread details in a format similar to stack trace
639
+ formattedText += ` thread_id: ${thread.thread_id}\n`;
640
+ formattedText += ` name: ${thread.name}\n`;
641
+ formattedText += ` state: ${thread.state}\n`;
642
+ formattedText += ` cpu_time: ${thread.cpu_time}\n`;
643
+ formattedText += ` memory_usage: ${thread.memory_usage}\n`;
644
+
645
+ // Add separator between threads
646
+ if (index < threadsData.length - 1) {
647
+ formattedText += '\n\n';
648
+ }
649
+ });
650
+ } catch (jsonError) {
651
+ // If not JSON, use the text as-is
652
+ formattedText = responseText;
653
+ }
654
+
655
+ contentDiv.textContent = formattedText;
656
+ } catch (error) {
657
+ console.error('Error loading threads:', error);
658
+ contentDiv.textContent = `Failed to load threads: ${error.message}`;
659
+ }
660
+ }