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 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
@@ -0,0 +1,587 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
"""
|
|
3
|
+
Base classes for health monitoring.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
# Standard
|
|
7
|
+
from abc import ABC, abstractmethod
|
|
8
|
+
from typing import TYPE_CHECKING, Dict, List, Optional
|
|
9
|
+
import threading
|
|
10
|
+
|
|
11
|
+
# First Party
|
|
12
|
+
from lmcache.logging import init_logger
|
|
13
|
+
from lmcache.v1.exceptions import IrrecoverableException
|
|
14
|
+
from lmcache.v1.health_monitor.constants import (
|
|
15
|
+
DEFAULT_FALLBACK_POLICY,
|
|
16
|
+
DEFAULT_PING_INTERVAL,
|
|
17
|
+
FallbackPolicy,
|
|
18
|
+
)
|
|
19
|
+
from lmcache.v1.periodic_thread import (
|
|
20
|
+
PeriodicThread,
|
|
21
|
+
PeriodicThreadRegistry,
|
|
22
|
+
ThreadLevel,
|
|
23
|
+
ThreadRunSummary,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
if TYPE_CHECKING:
|
|
27
|
+
# First Party
|
|
28
|
+
from lmcache.v1.manager import LMCacheManager
|
|
29
|
+
from lmcache.v1.storage_backend.local_cpu_backend import LocalCPUBackend
|
|
30
|
+
from lmcache.v1.storage_backend.storage_manager import StorageManager
|
|
31
|
+
|
|
32
|
+
logger = init_logger(__name__)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class HealthCheck(ABC):
|
|
36
|
+
"""
|
|
37
|
+
Abstract base class for health checks.
|
|
38
|
+
|
|
39
|
+
Subclasses should implement the check() method to perform specific
|
|
40
|
+
health checks. Each health check represents one aspect of system health.
|
|
41
|
+
|
|
42
|
+
Subclasses must also implement the create() classmethod
|
|
43
|
+
to create instances from a LMCacheManager.
|
|
44
|
+
|
|
45
|
+
Attributes:
|
|
46
|
+
fallback_policy: The fallback policy when this health check fails.
|
|
47
|
+
- RECOMPUTE: Skip all cache operations, fall back to recomputation
|
|
48
|
+
- LOCAL_CPU: Fall back to local CPU backend only
|
|
49
|
+
|
|
50
|
+
Example:
|
|
51
|
+
class DatabaseHealthCheck(HealthCheck):
|
|
52
|
+
def __init__(self, db_connection, fallback_policy=FallbackPolicy.RECOMPUTE):
|
|
53
|
+
self._fallback_policy = fallback_policy
|
|
54
|
+
self.db = db_connection
|
|
55
|
+
|
|
56
|
+
def name(self) -> str:
|
|
57
|
+
return "DatabaseHealthCheck"
|
|
58
|
+
|
|
59
|
+
def check(self) -> bool:
|
|
60
|
+
return self.db.ping()
|
|
61
|
+
|
|
62
|
+
@property
|
|
63
|
+
def fallback_policy(self) -> FallbackPolicy:
|
|
64
|
+
return self._fallback_policy
|
|
65
|
+
|
|
66
|
+
@classmethod
|
|
67
|
+
def create(
|
|
68
|
+
cls, manager: "LMCacheManager"
|
|
69
|
+
) -> List["HealthCheck"]:
|
|
70
|
+
# Create instances from manager's components
|
|
71
|
+
return [cls(manager.lmcache_engine.db_connection)]
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
@abstractmethod
|
|
75
|
+
def name(self) -> str:
|
|
76
|
+
"""Return the name of this health check"""
|
|
77
|
+
pass
|
|
78
|
+
|
|
79
|
+
@abstractmethod
|
|
80
|
+
def check(self) -> bool:
|
|
81
|
+
"""
|
|
82
|
+
Perform the health check.
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
bool: True if healthy, False otherwise
|
|
86
|
+
"""
|
|
87
|
+
pass
|
|
88
|
+
|
|
89
|
+
@property
|
|
90
|
+
def fallback_policy(self) -> FallbackPolicy:
|
|
91
|
+
"""
|
|
92
|
+
Return the fallback policy for this health check.
|
|
93
|
+
|
|
94
|
+
Default is RECOMPUTE. Subclasses can override this property
|
|
95
|
+
to return a different policy.
|
|
96
|
+
|
|
97
|
+
Returns:
|
|
98
|
+
FallbackPolicy: The fallback policy
|
|
99
|
+
"""
|
|
100
|
+
return DEFAULT_FALLBACK_POLICY
|
|
101
|
+
|
|
102
|
+
def should_skip(self) -> bool:
|
|
103
|
+
"""
|
|
104
|
+
Check if this health check should be skipped.
|
|
105
|
+
|
|
106
|
+
Override this method to conditionally skip checks
|
|
107
|
+
(e.g., if the component doesn't support health checks).
|
|
108
|
+
|
|
109
|
+
Returns:
|
|
110
|
+
bool: True if the check should be skipped, False otherwise
|
|
111
|
+
"""
|
|
112
|
+
return False
|
|
113
|
+
|
|
114
|
+
def get_bypass_backend_name(self) -> Optional[str]:
|
|
115
|
+
"""
|
|
116
|
+
Return the backend name to bypass when this health check fails
|
|
117
|
+
and fallback_policy is LOCAL_CPU.
|
|
118
|
+
|
|
119
|
+
Override this method to specify the backend name.
|
|
120
|
+
|
|
121
|
+
Returns:
|
|
122
|
+
Optional[str]: The backend name to bypass, or None if not applicable
|
|
123
|
+
"""
|
|
124
|
+
return None
|
|
125
|
+
|
|
126
|
+
@classmethod
|
|
127
|
+
@abstractmethod
|
|
128
|
+
def create(cls, manager: "LMCacheManager") -> List["HealthCheck"]:
|
|
129
|
+
"""
|
|
130
|
+
Create health check instance(s) from a LMCacheManager.
|
|
131
|
+
|
|
132
|
+
This method should extract the necessary components from the manager
|
|
133
|
+
and create one or more health check instances.
|
|
134
|
+
|
|
135
|
+
Args:
|
|
136
|
+
manager: The LMCacheManager instance
|
|
137
|
+
|
|
138
|
+
Returns:
|
|
139
|
+
List[HealthCheck]: List of health check instances.
|
|
140
|
+
Return empty list if the check is not applicable.
|
|
141
|
+
"""
|
|
142
|
+
pass
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
class HealthMonitor(PeriodicThread):
|
|
146
|
+
"""
|
|
147
|
+
Health monitor for the entire LMCache system.
|
|
148
|
+
|
|
149
|
+
This is the unified health monitor for the entire LMCache system.
|
|
150
|
+
It supports extensible health checks and provides a centralized way
|
|
151
|
+
to check the health status of the LMCacheManager.
|
|
152
|
+
|
|
153
|
+
The monitor automatically discovers and instantiates all HealthCheck
|
|
154
|
+
subclasses using their create() method.
|
|
155
|
+
|
|
156
|
+
The monitor runs in a background thread and periodically executes
|
|
157
|
+
all registered health checks. If any check fails, the system is
|
|
158
|
+
marked as unhealthy and appropriate fallback actions are taken
|
|
159
|
+
based on each check's fallback_policy.
|
|
160
|
+
|
|
161
|
+
Fallback Policies:
|
|
162
|
+
- RECOMPUTE: Mark system as unhealthy, skip all cache operations
|
|
163
|
+
- LOCAL_CPU: Bypass the failed backend, use local CPU with hot_cache enabled
|
|
164
|
+
|
|
165
|
+
Usage:
|
|
166
|
+
# Create a health monitor with manager
|
|
167
|
+
health_monitor = HealthMonitor(
|
|
168
|
+
manager=manager,
|
|
169
|
+
ping_interval=30.0
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
# Start monitoring
|
|
173
|
+
health_monitor.start()
|
|
174
|
+
|
|
175
|
+
# Check health status
|
|
176
|
+
if health_monitor.is_healthy():
|
|
177
|
+
# Perform normal operations
|
|
178
|
+
pass
|
|
179
|
+
|
|
180
|
+
# Stop monitoring when done
|
|
181
|
+
health_monitor.stop()
|
|
182
|
+
"""
|
|
183
|
+
|
|
184
|
+
def __init__(
|
|
185
|
+
self,
|
|
186
|
+
manager: "LMCacheManager",
|
|
187
|
+
ping_interval: float = DEFAULT_PING_INTERVAL,
|
|
188
|
+
):
|
|
189
|
+
# Initialize PeriodicThread base class
|
|
190
|
+
super().__init__(
|
|
191
|
+
name="health-monitor-thread",
|
|
192
|
+
interval=ping_interval,
|
|
193
|
+
level=ThreadLevel.CRITICAL,
|
|
194
|
+
init_wait=0.0,
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
self._manager = manager
|
|
198
|
+
self._health_checks: List[HealthCheck] = []
|
|
199
|
+
|
|
200
|
+
# Health status
|
|
201
|
+
self._healthy = True
|
|
202
|
+
self._health_lock = threading.RLock()
|
|
203
|
+
|
|
204
|
+
# Configuration (also stored in base class)
|
|
205
|
+
self._ping_interval = ping_interval
|
|
206
|
+
|
|
207
|
+
# Track which backends are currently bypassed due to health check failures
|
|
208
|
+
# Key: backend_name, Value: check_name that caused the bypass
|
|
209
|
+
self._bypassed_backends: Dict[str, str] = {}
|
|
210
|
+
self._bypass_lock = threading.RLock()
|
|
211
|
+
|
|
212
|
+
# Track original hot_cache setting before any LOCAL_CPU fallback
|
|
213
|
+
# This is a global setting, not per-backend
|
|
214
|
+
# None means no fallback is active, otherwise stores the original use_hot value
|
|
215
|
+
self._original_hot_cache: Optional[bool] = None
|
|
216
|
+
|
|
217
|
+
# Track previous health status per check for detecting recovery
|
|
218
|
+
self._previous_check_status: Dict[str, bool] = {}
|
|
219
|
+
|
|
220
|
+
# Auto-discover and instantiate health checks
|
|
221
|
+
self._discover_health_checks()
|
|
222
|
+
|
|
223
|
+
# Register with the global registry
|
|
224
|
+
PeriodicThreadRegistry.get_instance().register(self)
|
|
225
|
+
|
|
226
|
+
def _discover_health_checks(self) -> None:
|
|
227
|
+
"""
|
|
228
|
+
Discover all HealthCheck subclasses and instantiate them.
|
|
229
|
+
|
|
230
|
+
This method dynamically scans all modules in the checks package,
|
|
231
|
+
finds all HealthCheck subclasses and calls their `create()`
|
|
232
|
+
method to create instances.
|
|
233
|
+
"""
|
|
234
|
+
# Standard
|
|
235
|
+
import importlib
|
|
236
|
+
import inspect
|
|
237
|
+
import pkgutil
|
|
238
|
+
|
|
239
|
+
# First Party
|
|
240
|
+
# Import the checks package
|
|
241
|
+
import lmcache.v1.health_monitor.checks as checks_pkg
|
|
242
|
+
|
|
243
|
+
# Discover all modules in the checks package
|
|
244
|
+
for _, module_name, _ in pkgutil.iter_modules(checks_pkg.__path__):
|
|
245
|
+
# Skip private modules
|
|
246
|
+
if module_name.startswith("_"):
|
|
247
|
+
continue
|
|
248
|
+
|
|
249
|
+
try:
|
|
250
|
+
module = importlib.import_module(f"{checks_pkg.__name__}.{module_name}")
|
|
251
|
+
|
|
252
|
+
# Find all HealthCheck subclasses in the module
|
|
253
|
+
for _, obj in inspect.getmembers(module):
|
|
254
|
+
if (
|
|
255
|
+
inspect.isclass(obj)
|
|
256
|
+
and issubclass(obj, HealthCheck)
|
|
257
|
+
and obj != HealthCheck
|
|
258
|
+
):
|
|
259
|
+
try:
|
|
260
|
+
instances = obj.create(self._manager)
|
|
261
|
+
for instance in instances:
|
|
262
|
+
self._health_checks.append(instance)
|
|
263
|
+
# Initialize previous status as healthy
|
|
264
|
+
self._previous_check_status[instance.name()] = True
|
|
265
|
+
logger.info(
|
|
266
|
+
f"Registered health check: {instance.name()} "
|
|
267
|
+
f"with fallback_policy: {instance.fallback_policy}"
|
|
268
|
+
)
|
|
269
|
+
except Exception as e:
|
|
270
|
+
logger.warning(
|
|
271
|
+
f"Failed to create health check {obj.__name__}: {e}"
|
|
272
|
+
)
|
|
273
|
+
except ImportError as e:
|
|
274
|
+
logger.warning(f"Failed to import module {module_name}: {e}")
|
|
275
|
+
|
|
276
|
+
def get_health_checks(self) -> List[HealthCheck]:
|
|
277
|
+
"""Get all registered health checks"""
|
|
278
|
+
return list(self._health_checks)
|
|
279
|
+
|
|
280
|
+
def is_healthy(self) -> bool:
|
|
281
|
+
"""
|
|
282
|
+
Check if the system is currently healthy.
|
|
283
|
+
|
|
284
|
+
Returns:
|
|
285
|
+
bool: True if healthy, False otherwise
|
|
286
|
+
"""
|
|
287
|
+
with self._health_lock:
|
|
288
|
+
return self._healthy
|
|
289
|
+
|
|
290
|
+
def _set_healthy(self, healthy: bool) -> None:
|
|
291
|
+
"""Set the health status"""
|
|
292
|
+
with self._health_lock:
|
|
293
|
+
if self._healthy != healthy:
|
|
294
|
+
if healthy:
|
|
295
|
+
logger.info(
|
|
296
|
+
"HealthMonitor: System recovered, restoring normal operations"
|
|
297
|
+
)
|
|
298
|
+
else:
|
|
299
|
+
logger.warning(
|
|
300
|
+
"HealthMonitor: System unhealthy, entering degraded mode"
|
|
301
|
+
)
|
|
302
|
+
self._healthy = healthy
|
|
303
|
+
|
|
304
|
+
def _get_storage_manager(self) -> Optional["StorageManager"]:
|
|
305
|
+
"""Get the storage manager from the cache engine."""
|
|
306
|
+
engine = self._manager.lmcache_engine
|
|
307
|
+
if engine is None:
|
|
308
|
+
return None
|
|
309
|
+
return engine.storage_manager
|
|
310
|
+
|
|
311
|
+
def _get_local_cpu_backend(
|
|
312
|
+
self, storage_manager: "StorageManager"
|
|
313
|
+
) -> Optional["LocalCPUBackend"]:
|
|
314
|
+
"""
|
|
315
|
+
Get the LocalCPUBackend from the storage manager with proper type.
|
|
316
|
+
|
|
317
|
+
Args:
|
|
318
|
+
storage_manager: The storage manager instance
|
|
319
|
+
|
|
320
|
+
Returns:
|
|
321
|
+
Optional[LocalCPUBackend]: The LocalCPUBackend instance, or None
|
|
322
|
+
"""
|
|
323
|
+
# First Party
|
|
324
|
+
from lmcache.v1.storage_backend.local_cpu_backend import LocalCPUBackend
|
|
325
|
+
|
|
326
|
+
backend = storage_manager.local_cpu_backend
|
|
327
|
+
if backend is not None and isinstance(backend, LocalCPUBackend):
|
|
328
|
+
return backend
|
|
329
|
+
return None
|
|
330
|
+
|
|
331
|
+
def _apply_local_cpu_fallback(self, check: HealthCheck) -> None:
|
|
332
|
+
"""
|
|
333
|
+
Apply LOCAL_CPU fallback policy for a failed health check.
|
|
334
|
+
|
|
335
|
+
This will:
|
|
336
|
+
1. Enable bypass for the specified backend in StorageManager
|
|
337
|
+
2. Enable hot_cache for LocalCPUBackend (only on first fallback)
|
|
338
|
+
|
|
339
|
+
Args:
|
|
340
|
+
check: The health check that failed
|
|
341
|
+
"""
|
|
342
|
+
backend_name = check.get_bypass_backend_name()
|
|
343
|
+
if backend_name is None:
|
|
344
|
+
logger.warning(
|
|
345
|
+
f"Health check {check.name()} has LOCAL_CPU fallback but "
|
|
346
|
+
"get_bypass_backend_name() returned None"
|
|
347
|
+
)
|
|
348
|
+
return
|
|
349
|
+
|
|
350
|
+
storage_manager = self._get_storage_manager()
|
|
351
|
+
if storage_manager is None:
|
|
352
|
+
logger.warning("StorageManager is not available for fallback")
|
|
353
|
+
return
|
|
354
|
+
|
|
355
|
+
with self._bypass_lock:
|
|
356
|
+
if backend_name in self._bypassed_backends:
|
|
357
|
+
# Already bypassed
|
|
358
|
+
return
|
|
359
|
+
|
|
360
|
+
local_cpu = self._get_local_cpu_backend(storage_manager)
|
|
361
|
+
|
|
362
|
+
# Save original hot_cache setting only on the first fallback
|
|
363
|
+
# (when no backends are bypassed yet)
|
|
364
|
+
if len(self._bypassed_backends) == 0:
|
|
365
|
+
if local_cpu is not None:
|
|
366
|
+
self._original_hot_cache = local_cpu.use_hot
|
|
367
|
+
else:
|
|
368
|
+
self._original_hot_cache = None
|
|
369
|
+
|
|
370
|
+
# Enable bypass for the backend
|
|
371
|
+
storage_manager.set_backend_bypass(backend_name, True)
|
|
372
|
+
|
|
373
|
+
# Enable hot_cache for LocalCPUBackend
|
|
374
|
+
if local_cpu is not None:
|
|
375
|
+
local_cpu.use_hot = True
|
|
376
|
+
logger.info(
|
|
377
|
+
f"Enabled hot_cache for LocalCPUBackend due to "
|
|
378
|
+
f"{check.name()} failure"
|
|
379
|
+
)
|
|
380
|
+
|
|
381
|
+
# Record this backend as bypassed
|
|
382
|
+
self._bypassed_backends[backend_name] = check.name()
|
|
383
|
+
|
|
384
|
+
logger.info(
|
|
385
|
+
f"Applied LOCAL_CPU fallback for {check.name()}: "
|
|
386
|
+
f"bypassing {backend_name}"
|
|
387
|
+
)
|
|
388
|
+
|
|
389
|
+
def _recover_from_local_cpu_fallback(self, check: HealthCheck) -> None:
|
|
390
|
+
"""
|
|
391
|
+
Recover from LOCAL_CPU fallback when a health check passes again.
|
|
392
|
+
|
|
393
|
+
This will:
|
|
394
|
+
1. Disable bypass for the specified backend in StorageManager
|
|
395
|
+
2. Only when ALL backends have recovered:
|
|
396
|
+
- Restore original hot_cache setting for LocalCPUBackend
|
|
397
|
+
- Clear hot_cache if it was originally disabled
|
|
398
|
+
|
|
399
|
+
Args:
|
|
400
|
+
check: The health check that recovered
|
|
401
|
+
"""
|
|
402
|
+
backend_name = check.get_bypass_backend_name()
|
|
403
|
+
if backend_name is None:
|
|
404
|
+
return
|
|
405
|
+
|
|
406
|
+
storage_manager = self._get_storage_manager()
|
|
407
|
+
if storage_manager is None:
|
|
408
|
+
return
|
|
409
|
+
|
|
410
|
+
with self._bypass_lock:
|
|
411
|
+
if backend_name not in self._bypassed_backends:
|
|
412
|
+
# Not in bypassed state
|
|
413
|
+
return
|
|
414
|
+
|
|
415
|
+
check_name = self._bypassed_backends[backend_name]
|
|
416
|
+
|
|
417
|
+
# Verify this is the same check that caused the bypass
|
|
418
|
+
if check_name != check.name():
|
|
419
|
+
return
|
|
420
|
+
|
|
421
|
+
# Disable bypass for the backend
|
|
422
|
+
storage_manager.set_backend_bypass(backend_name, False)
|
|
423
|
+
|
|
424
|
+
# Remove from bypassed backends
|
|
425
|
+
del self._bypassed_backends[backend_name]
|
|
426
|
+
|
|
427
|
+
logger.info(
|
|
428
|
+
f"Recovered from LOCAL_CPU fallback for {check.name()}: "
|
|
429
|
+
f"restored {backend_name}"
|
|
430
|
+
)
|
|
431
|
+
|
|
432
|
+
# Only restore hot_cache when ALL backends have recovered
|
|
433
|
+
if len(self._bypassed_backends) == 0:
|
|
434
|
+
local_cpu = self._get_local_cpu_backend(storage_manager)
|
|
435
|
+
if local_cpu is not None and self._original_hot_cache is not None:
|
|
436
|
+
# First, restore the original hot_cache setting
|
|
437
|
+
# This prevents new data from being written during clear()
|
|
438
|
+
local_cpu.use_hot = self._original_hot_cache
|
|
439
|
+
logger.info(
|
|
440
|
+
f"Restored hot_cache setting to {self._original_hot_cache} "
|
|
441
|
+
f"for LocalCPUBackend (all backends restored)"
|
|
442
|
+
)
|
|
443
|
+
|
|
444
|
+
# Then, clear hot_cache if it was originally disabled
|
|
445
|
+
# At this point, use_hot is already False, so no new data
|
|
446
|
+
# will be written during the potentially long clear() operation
|
|
447
|
+
if not self._original_hot_cache:
|
|
448
|
+
local_cpu.clear()
|
|
449
|
+
logger.info(
|
|
450
|
+
"Cleared hot_cache for LocalCPUBackend during recovery "
|
|
451
|
+
"(all backends restored)"
|
|
452
|
+
)
|
|
453
|
+
# Reset original_hot_cache tracker
|
|
454
|
+
self._original_hot_cache = None
|
|
455
|
+
|
|
456
|
+
def _run_all_checks(self) -> bool:
|
|
457
|
+
"""
|
|
458
|
+
Run all health checks.
|
|
459
|
+
|
|
460
|
+
Returns:
|
|
461
|
+
bool: True if all checks pass (considering fallback policies),
|
|
462
|
+
False if any check with RECOMPUTE policy fails
|
|
463
|
+
|
|
464
|
+
Raises:
|
|
465
|
+
IrrecoverableException: If any check raises an irrecoverable error
|
|
466
|
+
"""
|
|
467
|
+
all_healthy = True
|
|
468
|
+
|
|
469
|
+
for check in self._health_checks:
|
|
470
|
+
if check.should_skip():
|
|
471
|
+
continue
|
|
472
|
+
|
|
473
|
+
check_name = check.name()
|
|
474
|
+
was_healthy = self._previous_check_status.get(check_name, True)
|
|
475
|
+
|
|
476
|
+
try:
|
|
477
|
+
is_healthy = check.check()
|
|
478
|
+
except IrrecoverableException:
|
|
479
|
+
logger.error(f"Health check {check_name} raised IrrecoverableException")
|
|
480
|
+
raise
|
|
481
|
+
except Exception as e:
|
|
482
|
+
logger.error(f"Health check {check_name} raised exception: {e}")
|
|
483
|
+
is_healthy = False
|
|
484
|
+
|
|
485
|
+
# Update previous status
|
|
486
|
+
self._previous_check_status[check_name] = is_healthy
|
|
487
|
+
|
|
488
|
+
if is_healthy:
|
|
489
|
+
# Check recovered
|
|
490
|
+
if not was_healthy:
|
|
491
|
+
logger.info(f"Health check {check_name} recovered")
|
|
492
|
+
# If this check was using LOCAL_CPU fallback, recover
|
|
493
|
+
if check.fallback_policy == FallbackPolicy.LOCAL_CPU:
|
|
494
|
+
self._recover_from_local_cpu_fallback(check)
|
|
495
|
+
else:
|
|
496
|
+
# Check failed
|
|
497
|
+
logger.warning(f"Health check failed: {check_name}")
|
|
498
|
+
|
|
499
|
+
if check.fallback_policy == FallbackPolicy.RECOMPUTE:
|
|
500
|
+
# RECOMPUTE policy: mark as unhealthy
|
|
501
|
+
all_healthy = False
|
|
502
|
+
elif check.fallback_policy == FallbackPolicy.LOCAL_CPU:
|
|
503
|
+
# LOCAL_CPU policy: apply fallback
|
|
504
|
+
self._apply_local_cpu_fallback(check)
|
|
505
|
+
# System is still considered healthy with LOCAL_CPU fallback
|
|
506
|
+
|
|
507
|
+
return all_healthy
|
|
508
|
+
|
|
509
|
+
def start(self) -> Optional[threading.Thread]:
|
|
510
|
+
"""
|
|
511
|
+
Start the health monitor thread.
|
|
512
|
+
|
|
513
|
+
Returns:
|
|
514
|
+
Optional[threading.Thread]: The started thread,
|
|
515
|
+
or None if no checks need monitoring
|
|
516
|
+
"""
|
|
517
|
+
# Check if we have any health checks that need to run
|
|
518
|
+
active_checks = [c for c in self._health_checks if not c.should_skip()]
|
|
519
|
+
if not active_checks:
|
|
520
|
+
logger.info("No active health checks to monitor, skipping monitor thread")
|
|
521
|
+
# Set last_summary even when not starting
|
|
522
|
+
self._last_summary = ThreadRunSummary(
|
|
523
|
+
success=True,
|
|
524
|
+
message="No active health checks to monitor, thread not started",
|
|
525
|
+
extra_info={
|
|
526
|
+
"total_checks": str(len(self._health_checks)),
|
|
527
|
+
"active_checks": "0",
|
|
528
|
+
"skipped": "true",
|
|
529
|
+
},
|
|
530
|
+
)
|
|
531
|
+
self._level = ThreadLevel.LOW
|
|
532
|
+
return None
|
|
533
|
+
|
|
534
|
+
# Use the base class start method
|
|
535
|
+
thread = super().start()
|
|
536
|
+
if thread is not None:
|
|
537
|
+
logger.info(
|
|
538
|
+
f"Started health monitor thread with "
|
|
539
|
+
f"{len(active_checks)} active checks, "
|
|
540
|
+
f"interval: {self._ping_interval}s"
|
|
541
|
+
)
|
|
542
|
+
return thread
|
|
543
|
+
|
|
544
|
+
def stop(self, timeout: float = 5.0) -> None:
|
|
545
|
+
"""Stop the health monitor thread"""
|
|
546
|
+
# Unregister from the global registry
|
|
547
|
+
PeriodicThreadRegistry.get_instance().unregister(self.name)
|
|
548
|
+
# Use base class stop method
|
|
549
|
+
super().stop(timeout)
|
|
550
|
+
|
|
551
|
+
def _execute(self) -> ThreadRunSummary:
|
|
552
|
+
"""
|
|
553
|
+
Execute one health check cycle.
|
|
554
|
+
|
|
555
|
+
This method is called by the PeriodicThread base class.
|
|
556
|
+
|
|
557
|
+
Returns:
|
|
558
|
+
ThreadRunSummary: Summary of the health check cycle
|
|
559
|
+
"""
|
|
560
|
+
try:
|
|
561
|
+
# Run all health checks
|
|
562
|
+
is_healthy = self._run_all_checks()
|
|
563
|
+
self._set_healthy(is_healthy)
|
|
564
|
+
|
|
565
|
+
# Build summary
|
|
566
|
+
failed_checks = [
|
|
567
|
+
name
|
|
568
|
+
for name, healthy in self._previous_check_status.items()
|
|
569
|
+
if not healthy
|
|
570
|
+
]
|
|
571
|
+
|
|
572
|
+
return ThreadRunSummary(
|
|
573
|
+
success=is_healthy,
|
|
574
|
+
message="All checks passed"
|
|
575
|
+
if is_healthy
|
|
576
|
+
else f"Failed checks: {failed_checks}",
|
|
577
|
+
extra_info={
|
|
578
|
+
"total_checks": str(len(self._health_checks)),
|
|
579
|
+
"failed_checks": str(len(failed_checks)),
|
|
580
|
+
"bypassed_backends": str(len(self._bypassed_backends)),
|
|
581
|
+
},
|
|
582
|
+
)
|
|
583
|
+
except IrrecoverableException as e:
|
|
584
|
+
logger.error(f"Irrecoverable error in health monitor: {e}")
|
|
585
|
+
self._set_healthy(False)
|
|
586
|
+
# Re-raise to stop the thread
|
|
587
|
+
raise
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|