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,304 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
"""
|
|
3
|
+
Health check for RemoteBackend.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
# Standard
|
|
7
|
+
from contextlib import contextmanager
|
|
8
|
+
from typing import TYPE_CHECKING, List, Optional
|
|
9
|
+
import asyncio
|
|
10
|
+
import time
|
|
11
|
+
|
|
12
|
+
# Third Party
|
|
13
|
+
import torch
|
|
14
|
+
|
|
15
|
+
# First Party
|
|
16
|
+
from lmcache.logging import init_logger
|
|
17
|
+
from lmcache.observability import LMCStatsMonitor
|
|
18
|
+
from lmcache.utils import CacheEngineKey
|
|
19
|
+
from lmcache.v1.health_monitor.base import HealthCheck
|
|
20
|
+
from lmcache.v1.health_monitor.constants import (
|
|
21
|
+
DEFAULT_FALLBACK_POLICY,
|
|
22
|
+
DEFAULT_GET_BLOCKING_FAILED_THRESHOLD,
|
|
23
|
+
DEFAULT_PING_TIMEOUT,
|
|
24
|
+
DEFAULT_WAITING_TIME_FOR_RECOVERY,
|
|
25
|
+
FALLBACK_POLICY_CONFIG_KEY,
|
|
26
|
+
GET_BLOCKING_FAILED_THRESHOLD_CONFIG_KEY,
|
|
27
|
+
PING_GENERIC_ERROR_CODE,
|
|
28
|
+
PING_TIMEOUT_CONFIG_KEY,
|
|
29
|
+
PING_TIMEOUT_ERROR_CODE,
|
|
30
|
+
WAITING_TIME_FOR_RECOVERY_CONFIG_KEY,
|
|
31
|
+
FallbackPolicy,
|
|
32
|
+
)
|
|
33
|
+
from lmcache.v1.storage_backend.connector import InstrumentedRemoteConnector
|
|
34
|
+
from lmcache.v1.storage_backend.connector.audit_connector import AuditConnector
|
|
35
|
+
|
|
36
|
+
if TYPE_CHECKING:
|
|
37
|
+
# First Party
|
|
38
|
+
from lmcache.v1.manager import LMCacheManager
|
|
39
|
+
from lmcache.v1.storage_backend.remote_backend import RemoteBackend
|
|
40
|
+
|
|
41
|
+
logger = init_logger(__name__)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class RemoteBackendHealthCheck(HealthCheck):
|
|
45
|
+
"""
|
|
46
|
+
Health check for RemoteBackend by pinging the remote connector.
|
|
47
|
+
|
|
48
|
+
This check verifies that the remote backend is reachable and responsive
|
|
49
|
+
by sending periodic ping requests.
|
|
50
|
+
|
|
51
|
+
Fallback Policies:
|
|
52
|
+
- RECOMPUTE (default): Skip all cache operations when
|
|
53
|
+
remote backend is unhealthy
|
|
54
|
+
- LOCAL_CPU: Bypass remote backend and use local CPU with hot_cache enabled
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
def __init__(
|
|
58
|
+
self,
|
|
59
|
+
backend: "RemoteBackend",
|
|
60
|
+
):
|
|
61
|
+
self.backend = backend
|
|
62
|
+
# Get fallback policy from config
|
|
63
|
+
fallback_policy_str = backend.config.get_extra_config_value(
|
|
64
|
+
FALLBACK_POLICY_CONFIG_KEY, DEFAULT_FALLBACK_POLICY.value
|
|
65
|
+
)
|
|
66
|
+
# Convert string to FallbackPolicy enum
|
|
67
|
+
if isinstance(fallback_policy_str, str):
|
|
68
|
+
try:
|
|
69
|
+
self._fallback_policy = FallbackPolicy(fallback_policy_str)
|
|
70
|
+
except ValueError:
|
|
71
|
+
logger.warning(
|
|
72
|
+
f"Invalid fallback_policy '{fallback_policy_str}' "
|
|
73
|
+
f"for {backend}, using default: "
|
|
74
|
+
f"{DEFAULT_FALLBACK_POLICY}"
|
|
75
|
+
)
|
|
76
|
+
self._fallback_policy = DEFAULT_FALLBACK_POLICY
|
|
77
|
+
elif isinstance(fallback_policy_str, FallbackPolicy):
|
|
78
|
+
self._fallback_policy = fallback_policy_str
|
|
79
|
+
self.failure_time: Optional[float] = None
|
|
80
|
+
self._stats_monitor = LMCStatsMonitor.GetOrCreate()
|
|
81
|
+
self._backend_name: Optional[str] = None
|
|
82
|
+
self._last_get_blocking_failed_count = 0
|
|
83
|
+
|
|
84
|
+
@classmethod
|
|
85
|
+
def create(cls, manager: "LMCacheManager") -> List[HealthCheck]:
|
|
86
|
+
"""
|
|
87
|
+
Create RemoteBackendHealthCheck instances from a LMCacheManager.
|
|
88
|
+
|
|
89
|
+
This method finds all RemoteBackend instances in the storage manager
|
|
90
|
+
and creates a health check for each one.
|
|
91
|
+
|
|
92
|
+
Args:
|
|
93
|
+
manager: The LMCacheManager instance
|
|
94
|
+
|
|
95
|
+
Returns:
|
|
96
|
+
List of RemoteBackendHealthCheck instances
|
|
97
|
+
"""
|
|
98
|
+
# Import here to avoid circular imports
|
|
99
|
+
# First Party
|
|
100
|
+
from lmcache.v1.storage_backend.remote_backend import RemoteBackend
|
|
101
|
+
|
|
102
|
+
instances: List[HealthCheck] = []
|
|
103
|
+
|
|
104
|
+
# Get engine from manager
|
|
105
|
+
engine = manager.lmcache_engine
|
|
106
|
+
if engine is None or engine.storage_manager is None:
|
|
107
|
+
return instances
|
|
108
|
+
|
|
109
|
+
for backend_name, backend in engine.storage_manager.storage_backends.items():
|
|
110
|
+
if isinstance(backend, RemoteBackend):
|
|
111
|
+
check = cls(backend)
|
|
112
|
+
check._backend_name = backend_name
|
|
113
|
+
instances.append(check)
|
|
114
|
+
logger.info(f"Created {check} for {backend_name}")
|
|
115
|
+
|
|
116
|
+
return instances
|
|
117
|
+
|
|
118
|
+
def name(self) -> str:
|
|
119
|
+
return f"RemoteBackendHealthCheck({self.backend.remote_url})"
|
|
120
|
+
|
|
121
|
+
@property
|
|
122
|
+
def fallback_policy(self) -> FallbackPolicy:
|
|
123
|
+
"""Return the fallback policy for this health check."""
|
|
124
|
+
return self._fallback_policy
|
|
125
|
+
|
|
126
|
+
def get_bypass_backend_name(self) -> Optional[str]:
|
|
127
|
+
"""
|
|
128
|
+
Return the backend name to bypass when this health check fails.
|
|
129
|
+
|
|
130
|
+
Returns:
|
|
131
|
+
Optional[str]: The backend name (e.g., "RemoteBackend")
|
|
132
|
+
"""
|
|
133
|
+
return self._backend_name
|
|
134
|
+
|
|
135
|
+
def _get_ping_timeout(self) -> float:
|
|
136
|
+
"""Get the ping timeout from the backend config."""
|
|
137
|
+
return self.backend.config.get_extra_config_value(
|
|
138
|
+
PING_TIMEOUT_CONFIG_KEY, DEFAULT_PING_TIMEOUT
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
def _try_reinitialize_connection(self) -> bool:
|
|
142
|
+
"""
|
|
143
|
+
Try to reinitialize the connection if connector is None.
|
|
144
|
+
|
|
145
|
+
Returns:
|
|
146
|
+
bool: True if connection was successfully initialized, False otherwise
|
|
147
|
+
"""
|
|
148
|
+
if self.backend.connection is not None:
|
|
149
|
+
return True
|
|
150
|
+
|
|
151
|
+
logger.warning("Connector is None, re-initializing connection.")
|
|
152
|
+
self.backend.init_connection()
|
|
153
|
+
|
|
154
|
+
return self.backend.connection is not None
|
|
155
|
+
|
|
156
|
+
def check(self) -> bool:
|
|
157
|
+
"""
|
|
158
|
+
Perform a health check on remote backend, which includes the following checks:
|
|
159
|
+
|
|
160
|
+
- get_blocking/batched_get_blocking, if failed count >= threshold,
|
|
161
|
+
which means check failed, update failure_time and return False.
|
|
162
|
+
If failure_time is not None, wait for more than`waiting_time_for_recovery`
|
|
163
|
+
seconds before resuming the check.
|
|
164
|
+
|
|
165
|
+
- ping, if connector supports ping, send a ping request to remote connector.
|
|
166
|
+
|
|
167
|
+
Returns:
|
|
168
|
+
bool: True if all checks succeeds, False otherwise
|
|
169
|
+
"""
|
|
170
|
+
# Try to reinitialize connection if needed
|
|
171
|
+
if not self._try_reinitialize_connection():
|
|
172
|
+
return False
|
|
173
|
+
|
|
174
|
+
# At this point, connector is guaranteed to be not None
|
|
175
|
+
connector = self.backend.connection
|
|
176
|
+
assert connector is not None
|
|
177
|
+
|
|
178
|
+
if self.failure_time is not None:
|
|
179
|
+
waiting_time = self.backend.config.get_extra_config_value(
|
|
180
|
+
WAITING_TIME_FOR_RECOVERY_CONFIG_KEY,
|
|
181
|
+
DEFAULT_WAITING_TIME_FOR_RECOVERY,
|
|
182
|
+
)
|
|
183
|
+
if (
|
|
184
|
+
time.time() - self.failure_time > waiting_time
|
|
185
|
+
and self._put_and_get_check()
|
|
186
|
+
):
|
|
187
|
+
# recover from get blocking failed
|
|
188
|
+
logger.info(
|
|
189
|
+
"Failure time: %s, current time: %s, "
|
|
190
|
+
"recover from get blocking failed",
|
|
191
|
+
self.failure_time,
|
|
192
|
+
time.time(),
|
|
193
|
+
)
|
|
194
|
+
self.failure_time = None
|
|
195
|
+
else:
|
|
196
|
+
logger.info(
|
|
197
|
+
"Failure time: %s, current time: %s, "
|
|
198
|
+
"still in get blocking failed recovery window",
|
|
199
|
+
self.failure_time,
|
|
200
|
+
time.time(),
|
|
201
|
+
)
|
|
202
|
+
return False
|
|
203
|
+
|
|
204
|
+
# Check read failed
|
|
205
|
+
current_get_blocking_failed_count = self.backend.get_blocking_failed_count
|
|
206
|
+
get_blocking_failed_count = (
|
|
207
|
+
current_get_blocking_failed_count - self._last_get_blocking_failed_count
|
|
208
|
+
)
|
|
209
|
+
self._last_get_blocking_failed_count = current_get_blocking_failed_count
|
|
210
|
+
threshold = self.backend.config.get_extra_config_value(
|
|
211
|
+
GET_BLOCKING_FAILED_THRESHOLD_CONFIG_KEY,
|
|
212
|
+
DEFAULT_GET_BLOCKING_FAILED_THRESHOLD,
|
|
213
|
+
)
|
|
214
|
+
if get_blocking_failed_count >= threshold:
|
|
215
|
+
logger.warning(
|
|
216
|
+
"Detected %s get blocking failed in interval, threshold: %s",
|
|
217
|
+
get_blocking_failed_count,
|
|
218
|
+
threshold,
|
|
219
|
+
)
|
|
220
|
+
self.failure_time = time.time()
|
|
221
|
+
return False
|
|
222
|
+
|
|
223
|
+
# If connector doesn't support ping, assume it's healthy
|
|
224
|
+
if not connector.support_ping():
|
|
225
|
+
return True
|
|
226
|
+
|
|
227
|
+
# Check ping
|
|
228
|
+
try:
|
|
229
|
+
start_time = time.perf_counter()
|
|
230
|
+
future = asyncio.run_coroutine_threadsafe(
|
|
231
|
+
connector.ping(), self.backend.loop
|
|
232
|
+
)
|
|
233
|
+
error_code = future.result(timeout=self._get_ping_timeout())
|
|
234
|
+
latency = (time.perf_counter() - start_time) * 1000
|
|
235
|
+
|
|
236
|
+
# Record ping latency
|
|
237
|
+
self._stats_monitor.update_remote_ping_latency(latency)
|
|
238
|
+
# Record error code (0 means success)
|
|
239
|
+
self._stats_monitor.update_remote_ping_error_code(error_code)
|
|
240
|
+
|
|
241
|
+
if error_code != 0:
|
|
242
|
+
logger.warning(f"Ping failed with error code: {error_code}")
|
|
243
|
+
return False
|
|
244
|
+
|
|
245
|
+
return True
|
|
246
|
+
|
|
247
|
+
except asyncio.TimeoutError:
|
|
248
|
+
logger.warning("Ping timeout")
|
|
249
|
+
self._stats_monitor.update_remote_ping_error_code(PING_TIMEOUT_ERROR_CODE)
|
|
250
|
+
return False
|
|
251
|
+
except Exception as e:
|
|
252
|
+
logger.error(f"Ping error: {e}")
|
|
253
|
+
self._stats_monitor.update_remote_ping_error_code(PING_GENERIC_ERROR_CODE)
|
|
254
|
+
return False
|
|
255
|
+
|
|
256
|
+
def _put_and_get_check(self) -> bool:
|
|
257
|
+
if self.backend.local_cpu_backend is None or self.backend.connection is None:
|
|
258
|
+
return False
|
|
259
|
+
|
|
260
|
+
with self._resource_manager() as (put_obj, get_obj):
|
|
261
|
+
if put_obj is None:
|
|
262
|
+
return False
|
|
263
|
+
if get_obj is None:
|
|
264
|
+
logger.warning("Get failed, the return value is None, check failed.")
|
|
265
|
+
return False
|
|
266
|
+
return torch.equal(put_obj.raw_tensor, get_obj.raw_tensor)
|
|
267
|
+
|
|
268
|
+
@contextmanager
|
|
269
|
+
def _resource_manager(self):
|
|
270
|
+
key = CacheEngineKey(
|
|
271
|
+
model_name="test",
|
|
272
|
+
world_size=1,
|
|
273
|
+
worker_id=0,
|
|
274
|
+
chunk_hash=0,
|
|
275
|
+
dtype=torch.bfloat16,
|
|
276
|
+
)
|
|
277
|
+
connector = self.backend.connection
|
|
278
|
+
if isinstance(connector, InstrumentedRemoteConnector):
|
|
279
|
+
connector = connector.getWrappedConnector()
|
|
280
|
+
if isinstance(connector, AuditConnector):
|
|
281
|
+
connector = connector.real_connector
|
|
282
|
+
shapes = connector.meta_shapes
|
|
283
|
+
dtypes = connector.meta_dtypes
|
|
284
|
+
fmt = connector.meta_fmt
|
|
285
|
+
put_obj, get_obj = None, None
|
|
286
|
+
try:
|
|
287
|
+
# put
|
|
288
|
+
put_obj = self.backend.local_cpu_backend.allocate(shapes, dtypes, fmt)
|
|
289
|
+
future = self.backend.submit_put_task(key, put_obj)
|
|
290
|
+
future.result(timeout=self._get_ping_timeout())
|
|
291
|
+
# get
|
|
292
|
+
get_obj = self.backend.get_blocking(key)
|
|
293
|
+
yield put_obj, get_obj
|
|
294
|
+
except asyncio.TimeoutError:
|
|
295
|
+
logger.warning("Put timeout, check failed.")
|
|
296
|
+
yield None, None
|
|
297
|
+
except Exception as e:
|
|
298
|
+
logger.error(f"Put error, check failed: {e}")
|
|
299
|
+
yield None, None
|
|
300
|
+
finally:
|
|
301
|
+
if put_obj is not None:
|
|
302
|
+
put_obj.ref_count_down()
|
|
303
|
+
if get_obj is not None:
|
|
304
|
+
get_obj.ref_count_down()
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
"""
|
|
3
|
+
Constants for health monitoring.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
# Standard
|
|
7
|
+
from enum import Enum
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class FallbackPolicy(str, Enum):
|
|
11
|
+
"""Fallback policy when health check fails."""
|
|
12
|
+
|
|
13
|
+
RECOMPUTE = "recompute" # Skip all cache operations, fall back to recomputation
|
|
14
|
+
LOCAL_CPU = "local_cpu" # Fall back to local CPU backend only
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# Ping error codes
|
|
18
|
+
PING_TIMEOUT_ERROR_CODE = -1
|
|
19
|
+
PING_GENERIC_ERROR_CODE = -2
|
|
20
|
+
|
|
21
|
+
# Configuration keys
|
|
22
|
+
PING_TIMEOUT_CONFIG_KEY = "ping_timeout"
|
|
23
|
+
PING_INTERVAL_CONFIG_KEY = "ping_interval"
|
|
24
|
+
FALLBACK_POLICY_CONFIG_KEY = "fallback_policy"
|
|
25
|
+
GET_BLOCKING_FAILED_THRESHOLD_CONFIG_KEY = "get_blocking_failed_threshold"
|
|
26
|
+
WAITING_TIME_FOR_RECOVERY_CONFIG_KEY = "waiting_time_for_recovery"
|
|
27
|
+
|
|
28
|
+
# Default values
|
|
29
|
+
DEFAULT_PING_TIMEOUT = 5.0
|
|
30
|
+
DEFAULT_PING_INTERVAL = 30.0
|
|
31
|
+
DEFAULT_FALLBACK_POLICY = FallbackPolicy.RECOMPUTE
|
|
32
|
+
DEFAULT_GET_BLOCKING_FAILED_THRESHOLD = 10
|
|
33
|
+
DEFAULT_WAITING_TIME_FOR_RECOVERY = 300.0
|
|
34
|
+
|
|
35
|
+
# Memory thresholds
|
|
36
|
+
DEFAULT_MEMORY_THRESHOLD_PERCENT = 95.0 # Unhealthy if memory usage > 95%
|
|
File without changes
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
# Standard
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import List, Literal, Optional
|
|
5
|
+
import importlib.util
|
|
6
|
+
import pkgutil
|
|
7
|
+
|
|
8
|
+
# Third Party
|
|
9
|
+
from fastapi import APIRouter
|
|
10
|
+
|
|
11
|
+
APICategory = Literal["common", "vllm", "controller"]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class APIRegistry:
|
|
15
|
+
"""
|
|
16
|
+
Automatically discovers and registers API routes by category
|
|
17
|
+
|
|
18
|
+
Categories:
|
|
19
|
+
- common: APIs that work for all components (metrics, logs, etc.)
|
|
20
|
+
- vllm: APIs specific to vLLM scheduler/worker
|
|
21
|
+
- controller: APIs specific to LMCache controller
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def __init__(self, app):
|
|
25
|
+
self.app = app
|
|
26
|
+
self.router = APIRouter()
|
|
27
|
+
|
|
28
|
+
def register_all_apis(self, categories: Optional[List[APICategory]] = None):
|
|
29
|
+
"""
|
|
30
|
+
Discover and register API modules from specified categories
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
categories: List of categories to register.
|
|
34
|
+
If None, registers all categories.
|
|
35
|
+
"""
|
|
36
|
+
if categories is None:
|
|
37
|
+
categories = ["common", "vllm", "controller"]
|
|
38
|
+
|
|
39
|
+
package_path = Path(__file__).parent
|
|
40
|
+
package_name = __package__
|
|
41
|
+
|
|
42
|
+
for category in categories:
|
|
43
|
+
category_path = package_path / category
|
|
44
|
+
if not category_path.exists():
|
|
45
|
+
continue
|
|
46
|
+
|
|
47
|
+
category_package = f"{package_name}.{category}"
|
|
48
|
+
|
|
49
|
+
for _, module_name, _ in pkgutil.iter_modules([str(category_path)]):
|
|
50
|
+
if module_name.endswith("_api"):
|
|
51
|
+
full_module_name = f"{category_package}.{module_name}"
|
|
52
|
+
module = importlib.import_module(full_module_name)
|
|
53
|
+
# Include the router if it exists
|
|
54
|
+
if hasattr(module, "router") and isinstance(
|
|
55
|
+
module.router, APIRouter
|
|
56
|
+
):
|
|
57
|
+
self.router.include_router(module.router)
|
|
58
|
+
|
|
59
|
+
self.app.include_router(self.router)
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
# Standard
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
import asyncio
|
|
5
|
+
import os
|
|
6
|
+
import threading
|
|
7
|
+
|
|
8
|
+
# Third Party
|
|
9
|
+
from fastapi import FastAPI
|
|
10
|
+
import uvicorn
|
|
11
|
+
|
|
12
|
+
# First Party
|
|
13
|
+
from lmcache.logging import init_logger
|
|
14
|
+
|
|
15
|
+
# Local
|
|
16
|
+
from .api_registry import APIRegistry
|
|
17
|
+
|
|
18
|
+
if TYPE_CHECKING:
|
|
19
|
+
# First Party
|
|
20
|
+
from lmcache.v1.manager import LMCacheManager
|
|
21
|
+
|
|
22
|
+
logger = init_logger(__name__)
|
|
23
|
+
|
|
24
|
+
app = FastAPI()
|
|
25
|
+
|
|
26
|
+
# Automatically register common, vllm, and controller APIs
|
|
27
|
+
registry = APIRegistry(app)
|
|
28
|
+
registry.register_all_apis(categories=["common", "vllm", "controller"])
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class InternalAPIServer:
|
|
32
|
+
def __init__(self, lmcache_manager: "LMCacheManager"):
|
|
33
|
+
lmcache_engine = lmcache_manager.lmcache_engine
|
|
34
|
+
|
|
35
|
+
# Check if lmcache_engine is None and handle accordingly
|
|
36
|
+
if lmcache_engine is None:
|
|
37
|
+
# Use manager's config directly when engine is not available
|
|
38
|
+
config = lmcache_manager.config
|
|
39
|
+
port_offset = 0 # Default for scheduler mode
|
|
40
|
+
else:
|
|
41
|
+
config = lmcache_engine.config
|
|
42
|
+
# 0 for scheduler, 1 for worker 0, 2 for worker 1, ...
|
|
43
|
+
port_offset = 1 + lmcache_engine.metadata.worker_id
|
|
44
|
+
|
|
45
|
+
self.port = config.internal_api_server_port_start + port_offset
|
|
46
|
+
self.socket_path_prefix = config.internal_api_server_socket_path_prefix
|
|
47
|
+
self.socket_path = (
|
|
48
|
+
f"{self.socket_path_prefix}_{self.port}"
|
|
49
|
+
if self.socket_path_prefix
|
|
50
|
+
else None
|
|
51
|
+
)
|
|
52
|
+
include_index_list = config.internal_api_server_include_index_list
|
|
53
|
+
|
|
54
|
+
self.enable = True
|
|
55
|
+
if not config.internal_api_server_enabled or (
|
|
56
|
+
include_index_list and port_offset not in include_index_list
|
|
57
|
+
):
|
|
58
|
+
logger.info(
|
|
59
|
+
f"Internal API server disabled. internal_api_server_enabled="
|
|
60
|
+
f"{config.internal_api_server_enabled}, port_offset={port_offset}, "
|
|
61
|
+
f"port={self.port}, socket_path={self.socket_path}, "
|
|
62
|
+
f"include_index_list={include_index_list}"
|
|
63
|
+
)
|
|
64
|
+
self.enable = False
|
|
65
|
+
return
|
|
66
|
+
|
|
67
|
+
uvicorn_config = {
|
|
68
|
+
"app": app,
|
|
69
|
+
"host": config.internal_api_server_host,
|
|
70
|
+
"loop": "uvloop",
|
|
71
|
+
"http": "httptools",
|
|
72
|
+
"access_log": config.get_extra_config_value(
|
|
73
|
+
"internal_api_server_access_log", True
|
|
74
|
+
),
|
|
75
|
+
"log_level": config.get_extra_config_value(
|
|
76
|
+
"internal_api_server_log_level", "warning"
|
|
77
|
+
),
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if self.socket_path:
|
|
81
|
+
self.server_log_info = f"socket {self.socket_path}"
|
|
82
|
+
logger.info(f"Init internal API server on {self.server_log_info}")
|
|
83
|
+
uvicorn_config["uds"] = self.socket_path
|
|
84
|
+
# Ensure socket directory exists
|
|
85
|
+
os.makedirs(os.path.dirname(self.socket_path), exist_ok=True)
|
|
86
|
+
# Remove existing socket file if exists
|
|
87
|
+
if os.path.exists(self.socket_path):
|
|
88
|
+
os.unlink(self.socket_path)
|
|
89
|
+
else:
|
|
90
|
+
self.server_log_info = f"port {self.port}"
|
|
91
|
+
logger.info(f"Init internal API server on {self.server_log_info}")
|
|
92
|
+
uvicorn_config["port"] = self.port
|
|
93
|
+
|
|
94
|
+
self.server = uvicorn.Server(uvicorn.Config(**uvicorn_config))
|
|
95
|
+
app.state.lmcache_adapter = lmcache_manager
|
|
96
|
+
|
|
97
|
+
async def run(self):
|
|
98
|
+
logger.info(f"Running LMCache internal API server on {self.server_log_info}")
|
|
99
|
+
if self.server:
|
|
100
|
+
await self.server.serve()
|
|
101
|
+
|
|
102
|
+
def start(self):
|
|
103
|
+
if not self.enable:
|
|
104
|
+
return
|
|
105
|
+
logger.info(f"Starting LMCache internal API server on {self.server_log_info}")
|
|
106
|
+
threading.Thread(
|
|
107
|
+
target=asyncio.run,
|
|
108
|
+
args=(self.run(),),
|
|
109
|
+
daemon=True,
|
|
110
|
+
name="api-server-thread",
|
|
111
|
+
).start()
|
|
112
|
+
|
|
113
|
+
def stop(self):
|
|
114
|
+
if not self.enable:
|
|
115
|
+
return
|
|
116
|
+
logger.info("Stopping LMCache internal API server")
|
|
117
|
+
if self.server:
|
|
118
|
+
self.server.should_exit = True
|
|
119
|
+
if self.socket_path and os.path.exists(self.socket_path):
|
|
120
|
+
os.unlink(self.socket_path)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
# Standard
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
|
|
6
|
+
# Third Party
|
|
7
|
+
from fastapi import APIRouter
|
|
8
|
+
from starlette.responses import PlainTextResponse
|
|
9
|
+
|
|
10
|
+
router = APIRouter()
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@router.get("/env")
|
|
14
|
+
async def get_env():
|
|
15
|
+
"""
|
|
16
|
+
Get all environment variables
|
|
17
|
+
"""
|
|
18
|
+
env_dict = dict(os.environ)
|
|
19
|
+
return PlainTextResponse(
|
|
20
|
+
content=json.dumps(env_dict, indent=2, sort_keys=True),
|
|
21
|
+
media_type="text/plain",
|
|
22
|
+
)
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
# Standard
|
|
3
|
+
from typing import Optional
|
|
4
|
+
import logging
|
|
5
|
+
|
|
6
|
+
# Third Party
|
|
7
|
+
from fastapi import APIRouter
|
|
8
|
+
from starlette.responses import PlainTextResponse
|
|
9
|
+
|
|
10
|
+
router = APIRouter()
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@router.get("/loglevel")
|
|
14
|
+
async def get_or_set_log_level(
|
|
15
|
+
logger_name: Optional[str] = None, level: Optional[str] = None
|
|
16
|
+
):
|
|
17
|
+
"""
|
|
18
|
+
Get or set the log level for a logger.
|
|
19
|
+
- No parameters: List all loggers and their levels.
|
|
20
|
+
- With logger_name: Get the level of the specified logger.
|
|
21
|
+
- With logger_name and level: Set the level of the specified logger.
|
|
22
|
+
"""
|
|
23
|
+
if not logger_name and not level:
|
|
24
|
+
# List all loggers and their levels
|
|
25
|
+
loggers = logging.Logger.manager.loggerDict
|
|
26
|
+
result = "=== Loggers and Levels ===\n"
|
|
27
|
+
for name, logger_obj in loggers.items():
|
|
28
|
+
if isinstance(logger_obj, logging.Logger):
|
|
29
|
+
result += f"{name}: {logging.getLevelName(logger_obj.level)}\n"
|
|
30
|
+
return PlainTextResponse(content=result, media_type="text/plain")
|
|
31
|
+
elif logger_name and not level:
|
|
32
|
+
# Get the level of the specified logger
|
|
33
|
+
target_logger = logging.getLogger(logger_name)
|
|
34
|
+
return PlainTextResponse(
|
|
35
|
+
content=f"{logger_name}: {logging.getLevelName(target_logger.level)}",
|
|
36
|
+
media_type="text/plain",
|
|
37
|
+
)
|
|
38
|
+
elif logger_name and level:
|
|
39
|
+
# Set the level of the specified logger
|
|
40
|
+
target_logger = logging.getLogger(logger_name)
|
|
41
|
+
try:
|
|
42
|
+
level_value = getattr(logging, level.upper())
|
|
43
|
+
target_logger.setLevel(level_value)
|
|
44
|
+
# Set the level of all handlers
|
|
45
|
+
for handler in target_logger.handlers:
|
|
46
|
+
handler.setLevel(level_value)
|
|
47
|
+
return PlainTextResponse(
|
|
48
|
+
content=f"Set {logger_name} level to {level.upper()} "
|
|
49
|
+
"(including all handlers)",
|
|
50
|
+
media_type="text/plain",
|
|
51
|
+
)
|
|
52
|
+
except AttributeError:
|
|
53
|
+
return PlainTextResponse(
|
|
54
|
+
content=f"Invalid log level: {level}",
|
|
55
|
+
media_type="text/plain",
|
|
56
|
+
status_code=400,
|
|
57
|
+
)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
# Third Party
|
|
3
|
+
from fastapi import APIRouter
|
|
4
|
+
from prometheus_client import REGISTRY, generate_latest
|
|
5
|
+
from starlette.requests import Request
|
|
6
|
+
from starlette.responses import PlainTextResponse
|
|
7
|
+
|
|
8
|
+
# First Party
|
|
9
|
+
from lmcache.observability import reset_observability_metrics
|
|
10
|
+
|
|
11
|
+
router = APIRouter()
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@router.get("/metrics")
|
|
15
|
+
async def get_metrics(request: Request):
|
|
16
|
+
"""
|
|
17
|
+
Provide Prometheus metrics data
|
|
18
|
+
"""
|
|
19
|
+
metrics_data = generate_latest(REGISTRY)
|
|
20
|
+
return PlainTextResponse(content=metrics_data, media_type="text/plain")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@router.post("/metrics/reset")
|
|
24
|
+
async def reset_metrics():
|
|
25
|
+
"""
|
|
26
|
+
Reset Prometheus metrics to their initial state.
|
|
27
|
+
"""
|
|
28
|
+
reset_observability_metrics()
|
|
29
|
+
return PlainTextResponse(content="ok", media_type="text/plain")
|