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.
- lmcache/__init__.py +84 -0
- lmcache/_version.py +24 -0
- lmcache/cli/__init__.py +1 -0
- lmcache/cli/commands/__init__.py +34 -0
- lmcache/cli/commands/base.py +157 -0
- lmcache/cli/commands/bench/__init__.py +557 -0
- lmcache/cli/commands/bench/engine_bench/__init__.py +1 -0
- lmcache/cli/commands/bench/engine_bench/config.py +245 -0
- lmcache/cli/commands/bench/engine_bench/interactive/__init__.py +274 -0
- lmcache/cli/commands/bench/engine_bench/interactive/config.json +10 -0
- lmcache/cli/commands/bench/engine_bench/interactive/schema.py +352 -0
- lmcache/cli/commands/bench/engine_bench/interactive/state.py +327 -0
- lmcache/cli/commands/bench/engine_bench/interactive/terminal.py +291 -0
- lmcache/cli/commands/bench/engine_bench/progress.py +145 -0
- lmcache/cli/commands/bench/engine_bench/request_sender.py +232 -0
- lmcache/cli/commands/bench/engine_bench/stats.py +275 -0
- lmcache/cli/commands/bench/engine_bench/workloads/__init__.py +153 -0
- lmcache/cli/commands/bench/engine_bench/workloads/base.py +122 -0
- lmcache/cli/commands/bench/engine_bench/workloads/long_doc_permutator.py +435 -0
- lmcache/cli/commands/bench/engine_bench/workloads/long_doc_qa.py +281 -0
- lmcache/cli/commands/bench/engine_bench/workloads/multi_round_chat.py +337 -0
- lmcache/cli/commands/bench/engine_bench/workloads/random_prefill.py +178 -0
- lmcache/cli/commands/describe.py +310 -0
- lmcache/cli/commands/kvcache.py +133 -0
- lmcache/cli/commands/mock.py +75 -0
- lmcache/cli/commands/ping.py +113 -0
- lmcache/cli/commands/query/__init__.py +155 -0
- lmcache/cli/commands/query/prompt.py +134 -0
- lmcache/cli/commands/query/request.py +357 -0
- lmcache/cli/commands/server.py +99 -0
- lmcache/cli/commands/tool/__init__.py +63 -0
- lmcache/cli/commands/tool/cache_simulator.py +113 -0
- lmcache/cli/commands/trace/__init__.py +505 -0
- lmcache/cli/commands/trace/dispatch.py +249 -0
- lmcache/cli/commands/trace/driver.py +372 -0
- lmcache/cli/commands/trace/stats.py +289 -0
- lmcache/cli/documents/lmcache.txt +11 -0
- lmcache/cli/main.py +42 -0
- lmcache/cli/metrics/__init__.py +29 -0
- lmcache/cli/metrics/formatter.py +171 -0
- lmcache/cli/metrics/handler.py +94 -0
- lmcache/cli/metrics/metrics.py +161 -0
- lmcache/cli/metrics/section.py +77 -0
- lmcache/connections.py +173 -0
- lmcache/integration/__init__.py +2 -0
- lmcache/integration/base_service_factory.py +165 -0
- lmcache/integration/request_telemetry/__init__.py +1 -0
- lmcache/integration/request_telemetry/base.py +51 -0
- lmcache/integration/request_telemetry/factory.py +113 -0
- lmcache/integration/request_telemetry/fastapi.py +109 -0
- lmcache/integration/request_telemetry/noop.py +35 -0
- lmcache/integration/sglang/__init__.py +2 -0
- lmcache/integration/sglang/sglang_adapter.py +326 -0
- lmcache/integration/sglang/utils.py +39 -0
- lmcache/integration/vllm/__init__.py +1 -0
- lmcache/integration/vllm/lmcache_connector_v1.py +213 -0
- lmcache/integration/vllm/lmcache_connector_v1_085.py +150 -0
- lmcache/integration/vllm/lmcache_mp_connector_0180.py +1072 -0
- lmcache/integration/vllm/tests/test_mm_hash_utils.py +112 -0
- lmcache/integration/vllm/utils.py +433 -0
- lmcache/integration/vllm/vllm_multi_process_adapter.py +1090 -0
- lmcache/integration/vllm/vllm_service_factory.py +339 -0
- lmcache/integration/vllm/vllm_v1_adapter.py +1713 -0
- lmcache/logging.py +107 -0
- lmcache/native_storage_ops.pyi +230 -0
- lmcache/non_cuda_equivalents.py +1424 -0
- lmcache/observability.py +1958 -0
- lmcache/storage_backend/serde/__init__.py +1 -0
- lmcache/storage_backend/serde/cachegen_basics.py +210 -0
- lmcache/storage_backend/serde/cachegen_decoder.py +207 -0
- lmcache/storage_backend/serde/cachegen_encoder.py +394 -0
- lmcache/storage_backend/serde/serde.py +75 -0
- lmcache/tools/__init__.py +1 -0
- lmcache/tools/cache_simulator/README.md +392 -0
- lmcache/tools/cache_simulator/__init__.py +1 -0
- lmcache/tools/cache_simulator/docs/simulate_example.png +0 -0
- lmcache/tools/cache_simulator/docs/sweep_example.png +0 -0
- lmcache/tools/cache_simulator/gen_bench_dataset.py +360 -0
- lmcache/tools/cache_simulator/lru_cache.py +124 -0
- lmcache/tools/cache_simulator/plot_hit_rate.py +231 -0
- lmcache/tools/cache_simulator/simulator.py +795 -0
- lmcache/tools/controller_benchmark/README.md +161 -0
- lmcache/tools/controller_benchmark/__init__.py +1 -0
- lmcache/tools/controller_benchmark/__main__.py +331 -0
- lmcache/tools/controller_benchmark/benchmark.py +660 -0
- lmcache/tools/controller_benchmark/config.py +44 -0
- lmcache/tools/controller_benchmark/constants.py +10 -0
- lmcache/tools/controller_benchmark/handlers/__init__.py +46 -0
- lmcache/tools/controller_benchmark/handlers/admit.py +52 -0
- lmcache/tools/controller_benchmark/handlers/base.py +47 -0
- lmcache/tools/controller_benchmark/handlers/deregister.py +49 -0
- lmcache/tools/controller_benchmark/handlers/evict.py +52 -0
- lmcache/tools/controller_benchmark/handlers/heartbeat.py +56 -0
- lmcache/tools/controller_benchmark/handlers/p2p_lookup.py +47 -0
- lmcache/tools/controller_benchmark/handlers/register.py +56 -0
- lmcache/tools/mp_status_viewer/__init__.py +1 -0
- lmcache/tools/mp_status_viewer/__main__.py +95 -0
- lmcache/usage_context.py +417 -0
- lmcache/utils.py +665 -0
- lmcache/v1/__init__.py +2 -0
- lmcache/v1/api_server/__init__.py +2 -0
- lmcache/v1/api_server/__main__.py +537 -0
- lmcache/v1/basic_check.py +112 -0
- lmcache/v1/cache_controller/__init__.py +9 -0
- lmcache/v1/cache_controller/commands/__init__.py +15 -0
- lmcache/v1/cache_controller/commands/base.py +35 -0
- lmcache/v1/cache_controller/commands/full_sync.py +49 -0
- lmcache/v1/cache_controller/config.py +176 -0
- lmcache/v1/cache_controller/controller_manager.py +535 -0
- lmcache/v1/cache_controller/controllers/__init__.py +11 -0
- lmcache/v1/cache_controller/controllers/full_sync_tracker.py +473 -0
- lmcache/v1/cache_controller/controllers/kv_controller.py +439 -0
- lmcache/v1/cache_controller/controllers/registration_controller.py +282 -0
- lmcache/v1/cache_controller/executor.py +463 -0
- lmcache/v1/cache_controller/frontend/static/css/style.css +201 -0
- lmcache/v1/cache_controller/frontend/static/img/logo.png +0 -0
- lmcache/v1/cache_controller/frontend/static/index.html +234 -0
- lmcache/v1/cache_controller/frontend/static/js/controller_app.js +660 -0
- lmcache/v1/cache_controller/full_sync_sender.py +475 -0
- lmcache/v1/cache_controller/locks.py +149 -0
- lmcache/v1/cache_controller/message.py +828 -0
- lmcache/v1/cache_controller/observability.py +208 -0
- lmcache/v1/cache_controller/utils.py +679 -0
- lmcache/v1/cache_controller/worker.py +665 -0
- lmcache/v1/cache_engine.py +2058 -0
- lmcache/v1/cache_interface.py +19 -0
- lmcache/v1/check/__init__.py +74 -0
- lmcache/v1/check/check_mode_gen.py +86 -0
- lmcache/v1/check/check_mode_test_l2_adapter.py +284 -0
- lmcache/v1/check/check_mode_test_remote.py +155 -0
- lmcache/v1/check/check_mode_test_storage_manager.py +142 -0
- lmcache/v1/check/utils.py +571 -0
- lmcache/v1/compute/__init__.py +2 -0
- lmcache/v1/compute/attention/__init__.py +0 -0
- lmcache/v1/compute/attention/abstract.py +39 -0
- lmcache/v1/compute/attention/flash_attn.py +129 -0
- lmcache/v1/compute/attention/flash_infer_sparse.py +284 -0
- lmcache/v1/compute/attention/metadata.py +85 -0
- lmcache/v1/compute/attention/utils.py +14 -0
- lmcache/v1/compute/blend/__init__.py +7 -0
- lmcache/v1/compute/blend/blender.py +168 -0
- lmcache/v1/compute/blend/metadata.py +34 -0
- lmcache/v1/compute/blend/utils.py +63 -0
- lmcache/v1/compute/models/__init__.py +0 -0
- lmcache/v1/compute/models/base.py +141 -0
- lmcache/v1/compute/models/llama.py +9 -0
- lmcache/v1/compute/models/qwen3.py +24 -0
- lmcache/v1/compute/models/utils.py +68 -0
- lmcache/v1/compute/positional_encoding.py +199 -0
- lmcache/v1/config.py +848 -0
- lmcache/v1/config_base.py +848 -0
- lmcache/v1/distributed/api.py +248 -0
- lmcache/v1/distributed/config.py +321 -0
- lmcache/v1/distributed/error.py +64 -0
- lmcache/v1/distributed/eviction.py +192 -0
- lmcache/v1/distributed/eviction_policy/__init__.py +21 -0
- lmcache/v1/distributed/eviction_policy/factory.py +27 -0
- lmcache/v1/distributed/eviction_policy/lru.py +244 -0
- lmcache/v1/distributed/eviction_policy/noop.py +50 -0
- lmcache/v1/distributed/internal_api.py +170 -0
- lmcache/v1/distributed/l1_manager.py +835 -0
- lmcache/v1/distributed/l2_adapters/__init__.py +67 -0
- lmcache/v1/distributed/l2_adapters/base.py +360 -0
- lmcache/v1/distributed/l2_adapters/config.py +385 -0
- lmcache/v1/distributed/l2_adapters/factory.py +205 -0
- lmcache/v1/distributed/l2_adapters/fs_l2_adapter.py +747 -0
- lmcache/v1/distributed/l2_adapters/fs_native_l2_adapter.py +167 -0
- lmcache/v1/distributed/l2_adapters/mock_l2_adapter.py +516 -0
- lmcache/v1/distributed/l2_adapters/mooncake_store_l2_adapter.py +135 -0
- lmcache/v1/distributed/l2_adapters/native_connector_l2_adapter.py +468 -0
- lmcache/v1/distributed/l2_adapters/native_plugin_l2_adapter.py +199 -0
- lmcache/v1/distributed/l2_adapters/nixl_store_dynamic_l2_adapter.py +831 -0
- lmcache/v1/distributed/l2_adapters/nixl_store_l2_adapter.py +983 -0
- lmcache/v1/distributed/l2_adapters/plugin_l2_adapter.py +210 -0
- lmcache/v1/distributed/l2_adapters/resp_l2_adapter.py +176 -0
- lmcache/v1/distributed/memory_manager.py +179 -0
- lmcache/v1/distributed/storage_controller.py +39 -0
- lmcache/v1/distributed/storage_controllers/__init__.py +43 -0
- lmcache/v1/distributed/storage_controllers/eviction_controller.py +242 -0
- lmcache/v1/distributed/storage_controllers/prefetch_controller.py +830 -0
- lmcache/v1/distributed/storage_controllers/prefetch_policy.py +193 -0
- lmcache/v1/distributed/storage_controllers/store_controller.py +452 -0
- lmcache/v1/distributed/storage_controllers/store_policy.py +213 -0
- lmcache/v1/distributed/storage_manager.py +532 -0
- lmcache/v1/event_manager.py +145 -0
- lmcache/v1/exceptions/__init__.py +16 -0
- lmcache/v1/gpu_connector/__init__.py +126 -0
- lmcache/v1/gpu_connector/gpu_connectors.py +1906 -0
- lmcache/v1/gpu_connector/gpu_ops.py +85 -0
- lmcache/v1/gpu_connector/hpu_connector.py +326 -0
- lmcache/v1/gpu_connector/mock_gpu_connector.py +67 -0
- lmcache/v1/gpu_connector/utils.py +890 -0
- lmcache/v1/gpu_connector/xpu_connectors.py +916 -0
- lmcache/v1/health_monitor/__init__.py +1 -0
- lmcache/v1/health_monitor/base.py +587 -0
- lmcache/v1/health_monitor/checks/__init__.py +1 -0
- lmcache/v1/health_monitor/checks/remote_backend_check.py +304 -0
- lmcache/v1/health_monitor/constants.py +36 -0
- lmcache/v1/internal_api_server/__init__.py +0 -0
- lmcache/v1/internal_api_server/api_registry.py +59 -0
- lmcache/v1/internal_api_server/api_server.py +120 -0
- lmcache/v1/internal_api_server/common/__init__.py +1 -0
- lmcache/v1/internal_api_server/common/env_api.py +22 -0
- lmcache/v1/internal_api_server/common/loglevel_api.py +57 -0
- lmcache/v1/internal_api_server/common/metrics_api.py +29 -0
- lmcache/v1/internal_api_server/common/periodic_thread_api.py +138 -0
- lmcache/v1/internal_api_server/common/run_script_api.py +73 -0
- lmcache/v1/internal_api_server/common/thread_api.py +63 -0
- lmcache/v1/internal_api_server/controller/__init__.py +1 -0
- lmcache/v1/internal_api_server/controller/key_stats_api.py +81 -0
- lmcache/v1/internal_api_server/controller/worker_info_api.py +136 -0
- lmcache/v1/internal_api_server/utils.py +43 -0
- lmcache/v1/internal_api_server/vllm/__init__.py +1 -0
- lmcache/v1/internal_api_server/vllm/backend_api.py +221 -0
- lmcache/v1/internal_api_server/vllm/bypass_api.py +204 -0
- lmcache/v1/internal_api_server/vllm/cache_api.py +895 -0
- lmcache/v1/internal_api_server/vllm/chunk_statistics_api.py +141 -0
- lmcache/v1/internal_api_server/vllm/conf_api.py +147 -0
- lmcache/v1/internal_api_server/vllm/freeze_api.py +172 -0
- lmcache/v1/internal_api_server/vllm/hot_cache_api.py +184 -0
- lmcache/v1/internal_api_server/vllm/inference_api.py +65 -0
- lmcache/v1/internal_api_server/vllm/load_fs_chunks_api.py +320 -0
- lmcache/v1/internal_api_server/vllm/lookup_api.py +145 -0
- lmcache/v1/internal_api_server/vllm/version_api.py +25 -0
- lmcache/v1/kv_layer_groups.py +267 -0
- lmcache/v1/lazy_memory_allocator.py +284 -0
- lmcache/v1/lookup_client/__init__.py +25 -0
- lmcache/v1/lookup_client/abstract_client.py +77 -0
- lmcache/v1/lookup_client/async_lookup_message.py +50 -0
- lmcache/v1/lookup_client/chunk_statistics_lookup_client.py +200 -0
- lmcache/v1/lookup_client/factory.py +251 -0
- lmcache/v1/lookup_client/hit_limit_lookup_client.py +86 -0
- lmcache/v1/lookup_client/lmcache_async_lookup_client.py +407 -0
- lmcache/v1/lookup_client/lmcache_lookup_client.py +285 -0
- lmcache/v1/lookup_client/lmcache_lookup_client_bypass.py +99 -0
- lmcache/v1/lookup_client/mooncake_lookup_client.py +87 -0
- lmcache/v1/lookup_client/record_strategies/__init__.py +77 -0
- lmcache/v1/lookup_client/record_strategies/base.py +327 -0
- lmcache/v1/lookup_client/record_strategies/file_hash.py +130 -0
- lmcache/v1/lookup_client/record_strategies/memory_bloom_filter.py +81 -0
- lmcache/v1/manager.py +539 -0
- lmcache/v1/memory_management.py +2619 -0
- lmcache/v1/metadata.py +114 -0
- lmcache/v1/mp_observability/AGENTS.override.md +21 -0
- lmcache/v1/mp_observability/README.md +204 -0
- lmcache/v1/mp_observability/config.py +340 -0
- lmcache/v1/mp_observability/event.py +100 -0
- lmcache/v1/mp_observability/event_bus.py +313 -0
- lmcache/v1/mp_observability/otel_init.py +145 -0
- lmcache/v1/mp_observability/subscribers/__init__.py +28 -0
- lmcache/v1/mp_observability/subscribers/logging/__init__.py +19 -0
- lmcache/v1/mp_observability/subscribers/logging/l1.py +56 -0
- lmcache/v1/mp_observability/subscribers/logging/l2.py +73 -0
- lmcache/v1/mp_observability/subscribers/logging/lookup_hash.py +209 -0
- lmcache/v1/mp_observability/subscribers/logging/mp_server.py +90 -0
- lmcache/v1/mp_observability/subscribers/logging/sm.py +59 -0
- lmcache/v1/mp_observability/subscribers/metrics/__init__.py +20 -0
- lmcache/v1/mp_observability/subscribers/metrics/l0_lifecycle.py +290 -0
- lmcache/v1/mp_observability/subscribers/metrics/l1.py +55 -0
- lmcache/v1/mp_observability/subscribers/metrics/l1_lifecycle.py +166 -0
- lmcache/v1/mp_observability/subscribers/metrics/l2.py +121 -0
- lmcache/v1/mp_observability/subscribers/metrics/sm.py +69 -0
- lmcache/v1/mp_observability/subscribers/tracing/__init__.py +12 -0
- lmcache/v1/mp_observability/subscribers/tracing/mp_server.py +333 -0
- lmcache/v1/mp_observability/subscribers/tracing/span_registry.py +148 -0
- lmcache/v1/mp_observability/trace/__init__.py +50 -0
- lmcache/v1/mp_observability/trace/codecs.py +255 -0
- lmcache/v1/mp_observability/trace/decorator.py +147 -0
- lmcache/v1/mp_observability/trace/format.py +132 -0
- lmcache/v1/mp_observability/trace/lifecycle.py +83 -0
- lmcache/v1/mp_observability/trace/reader.py +167 -0
- lmcache/v1/mp_observability/trace/recorder.py +300 -0
- lmcache/v1/multiprocess/__init__.py +0 -0
- lmcache/v1/multiprocess/affinity_pool.py +102 -0
- lmcache/v1/multiprocess/blend_server_v2.py +891 -0
- lmcache/v1/multiprocess/config.py +253 -0
- lmcache/v1/multiprocess/custom_types.py +281 -0
- lmcache/v1/multiprocess/futures.py +194 -0
- lmcache/v1/multiprocess/gpu_context.py +511 -0
- lmcache/v1/multiprocess/http_server.py +235 -0
- lmcache/v1/multiprocess/mp_runtime_plugin_launcher.py +130 -0
- lmcache/v1/multiprocess/mq.py +732 -0
- lmcache/v1/multiprocess/protocol.py +86 -0
- lmcache/v1/multiprocess/protocols/README.md +213 -0
- lmcache/v1/multiprocess/protocols/__init__.py +127 -0
- lmcache/v1/multiprocess/protocols/base.py +89 -0
- lmcache/v1/multiprocess/protocols/blend.py +109 -0
- lmcache/v1/multiprocess/protocols/blend_v2.py +57 -0
- lmcache/v1/multiprocess/protocols/controller.py +53 -0
- lmcache/v1/multiprocess/protocols/debug.py +34 -0
- lmcache/v1/multiprocess/protocols/engine.py +146 -0
- lmcache/v1/multiprocess/protocols/observability.py +39 -0
- lmcache/v1/multiprocess/server.py +1134 -0
- lmcache/v1/multiprocess/session.py +190 -0
- lmcache/v1/multiprocess/token_hasher.py +441 -0
- lmcache/v1/offload_server/__init__.py +17 -0
- lmcache/v1/offload_server/abstract_server.py +37 -0
- lmcache/v1/offload_server/message.py +30 -0
- lmcache/v1/offload_server/zmq_server.py +122 -0
- lmcache/v1/periodic_thread.py +579 -0
- lmcache/v1/pin_monitor.py +246 -0
- lmcache/v1/plugin/__init__.py +0 -0
- lmcache/v1/plugin/runtime_plugin_launcher.py +211 -0
- lmcache/v1/protocol.py +317 -0
- lmcache/v1/rpc/__init__.py +17 -0
- lmcache/v1/rpc/transport.py +105 -0
- lmcache/v1/rpc/zmq_transport.py +213 -0
- lmcache/v1/rpc_utils.py +165 -0
- lmcache/v1/server/__init__.py +2 -0
- lmcache/v1/server/__main__.py +170 -0
- lmcache/v1/server/storage_backend/__init__.py +21 -0
- lmcache/v1/server/storage_backend/abstract_backend.py +80 -0
- lmcache/v1/server/storage_backend/local_backend.py +75 -0
- lmcache/v1/server/utils.py +21 -0
- lmcache/v1/standalone/__init__.py +1 -0
- lmcache/v1/standalone/__main__.py +583 -0
- lmcache/v1/standalone/manager.py +80 -0
- lmcache/v1/standalone/standalone_service_factory.py +86 -0
- lmcache/v1/storage_backend/__init__.py +313 -0
- lmcache/v1/storage_backend/abstract_backend.py +445 -0
- lmcache/v1/storage_backend/audit_backend.py +233 -0
- lmcache/v1/storage_backend/batched_message_sender.py +222 -0
- lmcache/v1/storage_backend/cache_policy/__init__.py +45 -0
- lmcache/v1/storage_backend/cache_policy/base_policy.py +87 -0
- lmcache/v1/storage_backend/cache_policy/fifo.py +58 -0
- lmcache/v1/storage_backend/cache_policy/lfu.py +105 -0
- lmcache/v1/storage_backend/cache_policy/lru.py +81 -0
- lmcache/v1/storage_backend/cache_policy/mru.py +61 -0
- lmcache/v1/storage_backend/connector/__init__.py +443 -0
- lmcache/v1/storage_backend/connector/audit_adapter.py +77 -0
- lmcache/v1/storage_backend/connector/audit_connector.py +320 -0
- lmcache/v1/storage_backend/connector/base_connector.py +379 -0
- lmcache/v1/storage_backend/connector/blackhole_adapter.py +21 -0
- lmcache/v1/storage_backend/connector/blackhole_connector.py +37 -0
- lmcache/v1/storage_backend/connector/eic_adapter.py +31 -0
- lmcache/v1/storage_backend/connector/eic_connector.py +757 -0
- lmcache/v1/storage_backend/connector/external_adapter.py +79 -0
- lmcache/v1/storage_backend/connector/fs_adapter.py +51 -0
- lmcache/v1/storage_backend/connector/fs_connector.py +403 -0
- lmcache/v1/storage_backend/connector/infinistore_adapter.py +56 -0
- lmcache/v1/storage_backend/connector/infinistore_connector.py +177 -0
- lmcache/v1/storage_backend/connector/instrumented_connector.py +219 -0
- lmcache/v1/storage_backend/connector/lm_adapter.py +31 -0
- lmcache/v1/storage_backend/connector/lm_connector.py +176 -0
- lmcache/v1/storage_backend/connector/mock_adapter.py +57 -0
- lmcache/v1/storage_backend/connector/mock_connector.py +349 -0
- lmcache/v1/storage_backend/connector/mooncakestore_adapter.py +43 -0
- lmcache/v1/storage_backend/connector/mooncakestore_connector.py +614 -0
- lmcache/v1/storage_backend/connector/redis_adapter.py +181 -0
- lmcache/v1/storage_backend/connector/redis_connector.py +828 -0
- lmcache/v1/storage_backend/connector/s3_adapter.py +59 -0
- lmcache/v1/storage_backend/connector/s3_connector.py +699 -0
- lmcache/v1/storage_backend/connector/sagemaker_hyperpod_adapter.py +233 -0
- lmcache/v1/storage_backend/connector/sagemaker_hyperpod_connector.py +987 -0
- lmcache/v1/storage_backend/connector/valkey_adapter.py +114 -0
- lmcache/v1/storage_backend/connector/valkey_connector.py +627 -0
- lmcache/v1/storage_backend/gds_backend.py +1199 -0
- lmcache/v1/storage_backend/job_executor/__init__.py +0 -0
- lmcache/v1/storage_backend/job_executor/base_executor.py +34 -0
- lmcache/v1/storage_backend/job_executor/pq_executor.py +235 -0
- lmcache/v1/storage_backend/local_cpu_backend.py +810 -0
- lmcache/v1/storage_backend/local_disk_backend.py +656 -0
- lmcache/v1/storage_backend/maru_backend.py +734 -0
- lmcache/v1/storage_backend/naive_serde/__init__.py +50 -0
- lmcache/v1/storage_backend/naive_serde/cachegen_basics.py +133 -0
- lmcache/v1/storage_backend/naive_serde/cachegen_decoder.py +135 -0
- lmcache/v1/storage_backend/naive_serde/cachegen_encoder.py +83 -0
- lmcache/v1/storage_backend/naive_serde/kivi_serde.py +22 -0
- lmcache/v1/storage_backend/naive_serde/naive_serde.py +18 -0
- lmcache/v1/storage_backend/naive_serde/serde.py +37 -0
- lmcache/v1/storage_backend/native_clients/connector_client_base.py +165 -0
- lmcache/v1/storage_backend/native_clients/resp_client.py +35 -0
- lmcache/v1/storage_backend/nixl_storage_backend.py +1400 -0
- lmcache/v1/storage_backend/p2p_backend.py +788 -0
- lmcache/v1/storage_backend/path_sharder.py +117 -0
- lmcache/v1/storage_backend/pd_backend.py +646 -0
- lmcache/v1/storage_backend/plugins/dax_backend.py +1443 -0
- lmcache/v1/storage_backend/plugins/rust_raw_block_backend.py +1361 -0
- lmcache/v1/storage_backend/remote_backend.py +624 -0
- lmcache/v1/storage_backend/resp_client.py +227 -0
- lmcache/v1/storage_backend/storage_backend_listener.py +19 -0
- lmcache/v1/storage_backend/storage_manager.py +1352 -0
- lmcache/v1/system_detection.py +110 -0
- lmcache/v1/token_database.py +551 -0
- lmcache/v1/transfer_channel/__init__.py +83 -0
- lmcache/v1/transfer_channel/abstract.py +285 -0
- lmcache/v1/transfer_channel/mock_memory_channel.py +156 -0
- lmcache/v1/transfer_channel/nixl_channel.py +639 -0
- lmcache/v1/transfer_channel/py_socket_channel.py +260 -0
- lmcache/v1/transfer_channel/transfer_utils.py +63 -0
- lmcache/v1/utils/__init__.py +1 -0
- lmcache/v1/utils/bloom_filter.py +109 -0
- lmcache/v1/utils/cache_utils.py +125 -0
- lmcache_cli-0.4.5.dev0.dist-info/METADATA +185 -0
- lmcache_cli-0.4.5.dev0.dist-info/RECORD +399 -0
- lmcache_cli-0.4.5.dev0.dist-info/WHEEL +5 -0
- lmcache_cli-0.4.5.dev0.dist-info/entry_points.txt +2 -0
- lmcache_cli-0.4.5.dev0.dist-info/licenses/LICENSE +201 -0
- 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
|
+
}
|