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,624 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
# Standard
|
|
3
|
+
from concurrent.futures import Future, TimeoutError
|
|
4
|
+
from typing import Any, Callable, List, Optional, Sequence, Set
|
|
5
|
+
import asyncio
|
|
6
|
+
import threading
|
|
7
|
+
import time
|
|
8
|
+
|
|
9
|
+
# First Party
|
|
10
|
+
from lmcache.logging import init_logger
|
|
11
|
+
from lmcache.observability import LMCStatsMonitor, PrometheusLogger
|
|
12
|
+
from lmcache.utils import CacheEngineKey, _lmcache_nvtx_annotate
|
|
13
|
+
from lmcache.v1.config import LMCacheEngineConfig
|
|
14
|
+
from lmcache.v1.exceptions import IrrecoverableException
|
|
15
|
+
from lmcache.v1.memory_management import MemoryObj
|
|
16
|
+
from lmcache.v1.metadata import LMCacheMetadata
|
|
17
|
+
from lmcache.v1.storage_backend.abstract_backend import StorageBackendInterface
|
|
18
|
+
from lmcache.v1.storage_backend.connector import CreateConnector
|
|
19
|
+
from lmcache.v1.storage_backend.connector.base_connector import RemoteConnector
|
|
20
|
+
from lmcache.v1.storage_backend.local_cpu_backend import LocalCPUBackend
|
|
21
|
+
from lmcache.v1.storage_backend.naive_serde import CreateSerde
|
|
22
|
+
|
|
23
|
+
logger = init_logger(__name__)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class RemoteBackend(StorageBackendInterface):
|
|
27
|
+
def __init__(
|
|
28
|
+
self,
|
|
29
|
+
config: LMCacheEngineConfig,
|
|
30
|
+
metadata: LMCacheMetadata,
|
|
31
|
+
loop: asyncio.AbstractEventLoop,
|
|
32
|
+
local_cpu_backend: Optional[LocalCPUBackend],
|
|
33
|
+
dst_device: str = "cuda",
|
|
34
|
+
plugin_name: Optional[str] = None,
|
|
35
|
+
):
|
|
36
|
+
super().__init__(dst_device=dst_device)
|
|
37
|
+
self.put_tasks: Set[CacheEngineKey] = set()
|
|
38
|
+
self.lock = threading.Lock()
|
|
39
|
+
|
|
40
|
+
self.plugin_name = plugin_name
|
|
41
|
+
|
|
42
|
+
# Determine if we're using legacy remote_url or new plugin-based approach
|
|
43
|
+
if plugin_name is not None:
|
|
44
|
+
# Using plugin-based approach
|
|
45
|
+
self.remote_url = f"plugin://{plugin_name}"
|
|
46
|
+
logger.info(f"Creating RemoteBackend for plugin: {plugin_name}")
|
|
47
|
+
else:
|
|
48
|
+
# Legacy remote_url approach
|
|
49
|
+
if config.remote_url is None:
|
|
50
|
+
raise ValueError(
|
|
51
|
+
"remote_url must be provided when not using plugin_name"
|
|
52
|
+
)
|
|
53
|
+
self.remote_url = config.remote_url
|
|
54
|
+
|
|
55
|
+
self.local_cpu_backend = local_cpu_backend
|
|
56
|
+
|
|
57
|
+
self.loop = loop
|
|
58
|
+
self.config = config
|
|
59
|
+
self.metadata = metadata
|
|
60
|
+
|
|
61
|
+
# Re-establish connection only when the connection
|
|
62
|
+
# has been lost for 10 secs
|
|
63
|
+
self.connection: Optional[RemoteConnector] = None
|
|
64
|
+
self.min_reconnect_interval = 10
|
|
65
|
+
self.failure_time = -1000000.0
|
|
66
|
+
self.init_connection()
|
|
67
|
+
|
|
68
|
+
assert config.remote_serde is not None
|
|
69
|
+
self.serializer, self.deserializer = CreateSerde(
|
|
70
|
+
config.remote_serde, metadata, config
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
# Precompute MLA mode status
|
|
74
|
+
self._mla_worker_id_as0_mode = (
|
|
75
|
+
config.get_extra_config_value(
|
|
76
|
+
"remote_enable_mla_worker_id_as0", metadata.use_mla
|
|
77
|
+
)
|
|
78
|
+
and metadata.use_mla
|
|
79
|
+
and metadata.world_size > 1
|
|
80
|
+
and metadata.worker_id != 0
|
|
81
|
+
)
|
|
82
|
+
logger.info(f"metadata={metadata}")
|
|
83
|
+
logger.info(
|
|
84
|
+
f"Connected to remote storage at {config.remote_url}, "
|
|
85
|
+
f"remote_mla_worker_id_as_0 mode: {self._mla_worker_id_as0_mode}"
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
# TODO(Jiayi): If we want to have cache admission policies,
|
|
89
|
+
# we must make decision (whether to send or not) at the local side
|
|
90
|
+
|
|
91
|
+
self.stats_monitor = LMCStatsMonitor.GetOrCreate()
|
|
92
|
+
|
|
93
|
+
# NOTE: Health monitoring is now handled at the LMCacheEngine level
|
|
94
|
+
# through HealthMonitor. RemoteBackend no longer manages its own
|
|
95
|
+
# health monitoring. The HealthMonitor in LMCacheEngine will
|
|
96
|
+
# register RemoteBackendHealthCheck for each RemoteBackend.
|
|
97
|
+
|
|
98
|
+
self._setup_metrics()
|
|
99
|
+
|
|
100
|
+
self._get_blocking_failed_count = 0
|
|
101
|
+
self._put_failed_count = 0
|
|
102
|
+
|
|
103
|
+
def _setup_metrics(self):
|
|
104
|
+
prometheus_logger = PrometheusLogger.GetInstanceOrNone()
|
|
105
|
+
if prometheus_logger is not None:
|
|
106
|
+
prometheus_logger.remote_put_task_num.set_function(
|
|
107
|
+
lambda: len(self.put_tasks)
|
|
108
|
+
)
|
|
109
|
+
prometheus_logger.get_blocking_failed_count.set_function(
|
|
110
|
+
lambda: self._get_blocking_failed_count
|
|
111
|
+
)
|
|
112
|
+
prometheus_logger.put_failed_count.set_function(
|
|
113
|
+
lambda: self._put_failed_count
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
def __str__(self):
|
|
117
|
+
return self.__class__.__name__
|
|
118
|
+
|
|
119
|
+
def init_connection(self):
|
|
120
|
+
# Initialize connection
|
|
121
|
+
if self.connection is not None:
|
|
122
|
+
return
|
|
123
|
+
if (time.time() - self.failure_time) < self.min_reconnect_interval:
|
|
124
|
+
logger.warning(
|
|
125
|
+
"Connection will not be re-established yet "
|
|
126
|
+
"since it has not been long enough since "
|
|
127
|
+
"the last failure"
|
|
128
|
+
)
|
|
129
|
+
return
|
|
130
|
+
try:
|
|
131
|
+
# Determine the URL to use for connection
|
|
132
|
+
if self.plugin_name is not None:
|
|
133
|
+
# Using plugin-based approach
|
|
134
|
+
# Create a virtual URL that the adapter can recognize
|
|
135
|
+
url = f"plugin://{self.plugin_name}"
|
|
136
|
+
logger.info(f"Creating connector for plugin: {self.plugin_name}")
|
|
137
|
+
else:
|
|
138
|
+
# Legacy remote_url approach
|
|
139
|
+
if self.config.remote_url is None:
|
|
140
|
+
raise ValueError(
|
|
141
|
+
"remote_url must be provided when not using plugin_name"
|
|
142
|
+
)
|
|
143
|
+
url = self.config.remote_url
|
|
144
|
+
|
|
145
|
+
self.connection = CreateConnector(
|
|
146
|
+
url,
|
|
147
|
+
self.loop,
|
|
148
|
+
self.local_cpu_backend,
|
|
149
|
+
self.config,
|
|
150
|
+
self.metadata,
|
|
151
|
+
plugin_name=self.plugin_name,
|
|
152
|
+
)
|
|
153
|
+
logger.info(f"Connection initialized/re-established at {url}")
|
|
154
|
+
except IrrecoverableException:
|
|
155
|
+
logger.error("Irrecoverable error during connection initialization")
|
|
156
|
+
raise
|
|
157
|
+
except Exception as e:
|
|
158
|
+
with self.lock:
|
|
159
|
+
self.failure_time = time.time()
|
|
160
|
+
logger.warning(f"Failed to initialize/re-establish remote connection: {e}")
|
|
161
|
+
self.connection = None
|
|
162
|
+
|
|
163
|
+
def contains(self, key: CacheEngineKey, pin: bool = False) -> bool:
|
|
164
|
+
if self.connection is None:
|
|
165
|
+
logger.warning("Connection is None in contains, returning False")
|
|
166
|
+
return False
|
|
167
|
+
|
|
168
|
+
# For MLA worker id as 0 mode, use worker_id 0
|
|
169
|
+
if self._mla_worker_id_as0_mode:
|
|
170
|
+
key = key.with_new_worker_id(0)
|
|
171
|
+
|
|
172
|
+
try:
|
|
173
|
+
if self.config.extra_config is not None and self.config.extra_config.get(
|
|
174
|
+
"use_exists_sync", False
|
|
175
|
+
):
|
|
176
|
+
return self.connection.exists_sync(key)
|
|
177
|
+
else:
|
|
178
|
+
future = asyncio.run_coroutine_threadsafe(
|
|
179
|
+
self.connection.exists(key), self.loop
|
|
180
|
+
)
|
|
181
|
+
res = future.result()
|
|
182
|
+
return res
|
|
183
|
+
except Exception as e:
|
|
184
|
+
logger.warning(f"Remote connection failed in contains: {e}")
|
|
185
|
+
logger.warning("Returning False")
|
|
186
|
+
return False
|
|
187
|
+
|
|
188
|
+
def batched_contains(
|
|
189
|
+
self,
|
|
190
|
+
keys: List[CacheEngineKey],
|
|
191
|
+
pin: bool = False,
|
|
192
|
+
) -> int:
|
|
193
|
+
if self.connection is None:
|
|
194
|
+
logger.warning("Connection is None in batched_contains, returning 0")
|
|
195
|
+
return 0
|
|
196
|
+
|
|
197
|
+
if not self.connection.support_batched_contains():
|
|
198
|
+
return super().batched_contains(keys, pin)
|
|
199
|
+
|
|
200
|
+
if self._mla_worker_id_as0_mode:
|
|
201
|
+
keys = [key.with_new_worker_id(0) for key in keys]
|
|
202
|
+
|
|
203
|
+
try:
|
|
204
|
+
return self.connection.batched_contains(keys)
|
|
205
|
+
except Exception as e:
|
|
206
|
+
logger.warning(f"Remote connection failed in batched_contains: {e}")
|
|
207
|
+
return 0
|
|
208
|
+
|
|
209
|
+
def exists_in_put_tasks(self, key: CacheEngineKey) -> bool:
|
|
210
|
+
with self.lock:
|
|
211
|
+
return key in self.put_tasks
|
|
212
|
+
|
|
213
|
+
def put_callback(self, future: Future, key: CacheEngineKey):
|
|
214
|
+
with self.lock:
|
|
215
|
+
self.put_tasks.discard(key)
|
|
216
|
+
try:
|
|
217
|
+
future.result()
|
|
218
|
+
except Exception as e:
|
|
219
|
+
self._put_failed_count += 1
|
|
220
|
+
logger.error(f"Put task failed for key {key}: {e}")
|
|
221
|
+
|
|
222
|
+
def submit_put_task(
|
|
223
|
+
self,
|
|
224
|
+
key: CacheEngineKey,
|
|
225
|
+
memory_obj: MemoryObj,
|
|
226
|
+
on_complete_callback: Optional[Callable[[CacheEngineKey], None]] = None,
|
|
227
|
+
) -> Future:
|
|
228
|
+
"""
|
|
229
|
+
Submit a put task to store KV cache to remote storage asynchronously.
|
|
230
|
+
|
|
231
|
+
:param on_complete_callback: Optional callback invoked after the remote
|
|
232
|
+
write completes. Callback exceptions are caught and logged.
|
|
233
|
+
"""
|
|
234
|
+
|
|
235
|
+
def create_immediate_empty_future() -> Future:
|
|
236
|
+
f: Future = Future()
|
|
237
|
+
f.set_result(None)
|
|
238
|
+
return f
|
|
239
|
+
|
|
240
|
+
if self.connection is None:
|
|
241
|
+
logger.warning("Connection is None in submit_put_task, returning None")
|
|
242
|
+
return create_immediate_empty_future()
|
|
243
|
+
|
|
244
|
+
# If MLA worker id as 0 mode is enabled, skip put tasks
|
|
245
|
+
if self._mla_worker_id_as0_mode:
|
|
246
|
+
return create_immediate_empty_future()
|
|
247
|
+
|
|
248
|
+
if self.exists_in_put_tasks(key):
|
|
249
|
+
return create_immediate_empty_future()
|
|
250
|
+
|
|
251
|
+
memory_obj.ref_count_up()
|
|
252
|
+
|
|
253
|
+
with self.lock:
|
|
254
|
+
self.put_tasks.add(key)
|
|
255
|
+
|
|
256
|
+
compressed_memory_obj = self.serializer.serialize(memory_obj)
|
|
257
|
+
memory_obj.ref_count_down()
|
|
258
|
+
|
|
259
|
+
def put_done_callback(f: Future) -> None:
|
|
260
|
+
self.put_callback(f, key)
|
|
261
|
+
if on_complete_callback is not None:
|
|
262
|
+
try:
|
|
263
|
+
on_complete_callback(key)
|
|
264
|
+
except Exception as e:
|
|
265
|
+
logger.warning(f"on_complete_callback failed for key {key}: {e}")
|
|
266
|
+
|
|
267
|
+
# NOTE: No need to do error handling here
|
|
268
|
+
# since the `future` is never waited
|
|
269
|
+
future = asyncio.run_coroutine_threadsafe(
|
|
270
|
+
self.connection.put(key, compressed_memory_obj), self.loop
|
|
271
|
+
)
|
|
272
|
+
future.add_done_callback(put_done_callback)
|
|
273
|
+
return future
|
|
274
|
+
|
|
275
|
+
def batched_put_callback(self, future: Future, keys: List[CacheEngineKey]):
|
|
276
|
+
"""
|
|
277
|
+
Callback function for batched put tasks.
|
|
278
|
+
"""
|
|
279
|
+
with self.lock:
|
|
280
|
+
self.put_tasks.difference_update(keys)
|
|
281
|
+
|
|
282
|
+
def batched_submit_put_task(
|
|
283
|
+
self,
|
|
284
|
+
keys: Sequence[CacheEngineKey],
|
|
285
|
+
memory_objs: List[MemoryObj],
|
|
286
|
+
transfer_spec: Any = None,
|
|
287
|
+
on_complete_callback: Optional[Callable[[CacheEngineKey], None]] = None,
|
|
288
|
+
) -> None:
|
|
289
|
+
"""
|
|
290
|
+
Submit batched put tasks to store KV caches to remote storage.
|
|
291
|
+
|
|
292
|
+
:param on_complete_callback: Optional callback invoked once per key
|
|
293
|
+
after that key's write completes (not once per batch).
|
|
294
|
+
"""
|
|
295
|
+
if self.connection is None:
|
|
296
|
+
logger.warning(
|
|
297
|
+
"Connection is None in batched_submit_put_task, returning None"
|
|
298
|
+
)
|
|
299
|
+
return
|
|
300
|
+
if self.connection.support_batched_put():
|
|
301
|
+
if self._mla_worker_id_as0_mode:
|
|
302
|
+
return
|
|
303
|
+
|
|
304
|
+
# First, increment reference counts for all objects
|
|
305
|
+
for memory_obj in memory_objs:
|
|
306
|
+
memory_obj.ref_count_up()
|
|
307
|
+
|
|
308
|
+
compressed_memory_objs = []
|
|
309
|
+
try:
|
|
310
|
+
for memory_obj in memory_objs:
|
|
311
|
+
compressed_memory_objs.append(self.serializer.serialize(memory_obj))
|
|
312
|
+
finally:
|
|
313
|
+
# Always decrement reference counts for all objects,
|
|
314
|
+
# regardless of whether serialization succeeded or failed
|
|
315
|
+
for memory_obj in memory_objs:
|
|
316
|
+
memory_obj.ref_count_down()
|
|
317
|
+
|
|
318
|
+
def batched_done_callback(f: Future) -> None:
|
|
319
|
+
self.batched_put_callback(f, list(keys))
|
|
320
|
+
# Invoke per-key callback for each key in the batch
|
|
321
|
+
if on_complete_callback is not None:
|
|
322
|
+
for key in keys:
|
|
323
|
+
try:
|
|
324
|
+
on_complete_callback(key)
|
|
325
|
+
except Exception as e:
|
|
326
|
+
logger.warning(
|
|
327
|
+
f"on_complete_callback failed for key {key}: {e}"
|
|
328
|
+
)
|
|
329
|
+
|
|
330
|
+
future = asyncio.run_coroutine_threadsafe(
|
|
331
|
+
self.connection.batched_put(keys, compressed_memory_objs), # type: ignore
|
|
332
|
+
self.loop,
|
|
333
|
+
)
|
|
334
|
+
future.add_done_callback(batched_done_callback)
|
|
335
|
+
else:
|
|
336
|
+
for key, memory_obj in zip(keys, memory_objs, strict=False):
|
|
337
|
+
self.submit_put_task(
|
|
338
|
+
key, memory_obj, on_complete_callback=on_complete_callback
|
|
339
|
+
)
|
|
340
|
+
|
|
341
|
+
@_lmcache_nvtx_annotate
|
|
342
|
+
def get_blocking(
|
|
343
|
+
self,
|
|
344
|
+
key: CacheEngineKey,
|
|
345
|
+
) -> Optional[MemoryObj]:
|
|
346
|
+
"""
|
|
347
|
+
Blocking get function.
|
|
348
|
+
"""
|
|
349
|
+
# Check if local_cpu_backend is available (required for memory allocation)
|
|
350
|
+
if self.local_cpu_backend is None:
|
|
351
|
+
logger.warning(
|
|
352
|
+
"local_cpu_backend is None in get_blocking "
|
|
353
|
+
"(likely scheduler role), returning None"
|
|
354
|
+
)
|
|
355
|
+
return None
|
|
356
|
+
|
|
357
|
+
if self.connection is None:
|
|
358
|
+
logger.warning("Connection is None in get_blocking, returning None")
|
|
359
|
+
return None
|
|
360
|
+
# For MLA worker id as 0 mode, use worker_id 0
|
|
361
|
+
if self._mla_worker_id_as0_mode:
|
|
362
|
+
key = key.with_new_worker_id(0)
|
|
363
|
+
t1 = time.perf_counter()
|
|
364
|
+
future = asyncio.run_coroutine_threadsafe(self.connection.get(key), self.loop)
|
|
365
|
+
|
|
366
|
+
try:
|
|
367
|
+
memory_obj = future.result(self.config.blocking_timeout_secs)
|
|
368
|
+
except Exception as e:
|
|
369
|
+
if isinstance(e, TimeoutError):
|
|
370
|
+
logger.warning("get blocking timeout, trigger cancel the future task")
|
|
371
|
+
future.cancel()
|
|
372
|
+
logger.warning("Error occurred in get_blocking: %s, return None", e)
|
|
373
|
+
memory_obj = None
|
|
374
|
+
|
|
375
|
+
t2 = time.perf_counter()
|
|
376
|
+
self.stats_monitor.update_interval_remote_time_to_get_sync((t2 - t1) * 1000)
|
|
377
|
+
if memory_obj is None:
|
|
378
|
+
self._get_blocking_failed_count += 1
|
|
379
|
+
return None
|
|
380
|
+
decompressed_memory_obj = self.deserializer.deserialize(memory_obj)
|
|
381
|
+
t3 = time.perf_counter()
|
|
382
|
+
logger.debug(
|
|
383
|
+
"Get takes %.6f msec, deserialization takes %.6f msec",
|
|
384
|
+
(t2 - t1) * 1000,
|
|
385
|
+
(t3 - t2) * 1000,
|
|
386
|
+
)
|
|
387
|
+
return decompressed_memory_obj
|
|
388
|
+
|
|
389
|
+
@property
|
|
390
|
+
def get_blocking_failed_count(self):
|
|
391
|
+
return self._get_blocking_failed_count
|
|
392
|
+
|
|
393
|
+
@property
|
|
394
|
+
def put_failed_count(self):
|
|
395
|
+
return self._put_failed_count
|
|
396
|
+
|
|
397
|
+
def batched_get_blocking(
|
|
398
|
+
self,
|
|
399
|
+
keys: List[CacheEngineKey],
|
|
400
|
+
) -> List[Optional[MemoryObj]]:
|
|
401
|
+
# Check if local_cpu_backend is available (required for memory allocation)
|
|
402
|
+
if self.local_cpu_backend is None:
|
|
403
|
+
logger.warning(
|
|
404
|
+
"local_cpu_backend is None in batched_get_blocking "
|
|
405
|
+
"(likely scheduler role), returning None list"
|
|
406
|
+
)
|
|
407
|
+
return [None] * len(keys)
|
|
408
|
+
|
|
409
|
+
if self.connection is None:
|
|
410
|
+
logger.warning("Connection is None in batched_get_blocking, returning None")
|
|
411
|
+
return [None] * len(keys)
|
|
412
|
+
|
|
413
|
+
# For MLA worker id as 0 mode, use worker_id 0
|
|
414
|
+
if self._mla_worker_id_as0_mode:
|
|
415
|
+
keys = [key.with_new_worker_id(0) for key in keys]
|
|
416
|
+
|
|
417
|
+
t1 = time.perf_counter()
|
|
418
|
+
# batched get
|
|
419
|
+
if self.connection.support_batched_get():
|
|
420
|
+
future = asyncio.run_coroutine_threadsafe(
|
|
421
|
+
self.connection.batched_get(keys), self.loop
|
|
422
|
+
)
|
|
423
|
+
try:
|
|
424
|
+
memory_objs = future.result(self.config.blocking_timeout_secs)
|
|
425
|
+
except Exception as e:
|
|
426
|
+
if isinstance(e, TimeoutError):
|
|
427
|
+
logger.warning(
|
|
428
|
+
"batched get blocking timeout, trigger cancel the future task"
|
|
429
|
+
)
|
|
430
|
+
future.cancel()
|
|
431
|
+
else:
|
|
432
|
+
logger.warning(
|
|
433
|
+
f"Error occurred in batched_get_blocking: {e}, "
|
|
434
|
+
f"returning None list"
|
|
435
|
+
)
|
|
436
|
+
memory_objs = [None] * len(keys)
|
|
437
|
+
else:
|
|
438
|
+
remote_backend_individual_get_stats: dict[
|
|
439
|
+
CacheEngineKey, dict[str, float]
|
|
440
|
+
] = {}
|
|
441
|
+
retrieve_stats = self.stats_monitor.get_current_retrieve_stats()
|
|
442
|
+
if retrieve_stats is not None:
|
|
443
|
+
retrieve_stats.detailed_metrics[
|
|
444
|
+
"remote_backend_individual_get_stats"
|
|
445
|
+
] = remote_backend_individual_get_stats
|
|
446
|
+
|
|
447
|
+
futures = [
|
|
448
|
+
asyncio.run_coroutine_threadsafe(self.connection.get(key), self.loop)
|
|
449
|
+
for key in keys
|
|
450
|
+
]
|
|
451
|
+
memory_objs = []
|
|
452
|
+
failed = False
|
|
453
|
+
for fut in futures:
|
|
454
|
+
if not failed:
|
|
455
|
+
try:
|
|
456
|
+
memory_obj = fut.result(self.config.blocking_timeout_secs)
|
|
457
|
+
except Exception as e:
|
|
458
|
+
failed = True
|
|
459
|
+
if isinstance(e, TimeoutError):
|
|
460
|
+
logger.warning(
|
|
461
|
+
"get blocking timeout, trigger cancel the future task"
|
|
462
|
+
)
|
|
463
|
+
fut.cancel()
|
|
464
|
+
else:
|
|
465
|
+
logger.warning(
|
|
466
|
+
f"Error occurred in get_blocking: {e}, returning None"
|
|
467
|
+
)
|
|
468
|
+
memory_obj = None
|
|
469
|
+
memory_objs.append(memory_obj)
|
|
470
|
+
else:
|
|
471
|
+
memory_objs.append(None)
|
|
472
|
+
fut.cancel()
|
|
473
|
+
|
|
474
|
+
t2 = time.perf_counter()
|
|
475
|
+
duration = t2 - t1
|
|
476
|
+
self.stats_monitor.update_interval_remote_time_to_get_sync(duration * 1000)
|
|
477
|
+
|
|
478
|
+
retrieve_stats = self.stats_monitor.get_current_retrieve_stats()
|
|
479
|
+
if retrieve_stats is not None:
|
|
480
|
+
retrieve_stats.detailed_metrics[
|
|
481
|
+
"remote_backend_batched_get_blocking_time"
|
|
482
|
+
] = (
|
|
483
|
+
retrieve_stats.detailed_metrics.get(
|
|
484
|
+
"remote_backend_batched_get_blocking_time", 0.0
|
|
485
|
+
)
|
|
486
|
+
+ duration
|
|
487
|
+
)
|
|
488
|
+
decompressed_memory_objs: list[Optional[MemoryObj]] = []
|
|
489
|
+
error_happened = False
|
|
490
|
+
for memory_obj in memory_objs:
|
|
491
|
+
if memory_obj is None:
|
|
492
|
+
error_happened = True
|
|
493
|
+
decompressed_memory_objs.append(None)
|
|
494
|
+
else:
|
|
495
|
+
decompressed_memory_objs.append(
|
|
496
|
+
self.deserializer.deserialize(memory_obj)
|
|
497
|
+
)
|
|
498
|
+
if error_happened:
|
|
499
|
+
self._get_blocking_failed_count += 1
|
|
500
|
+
|
|
501
|
+
assert len(decompressed_memory_objs) == len(keys), (
|
|
502
|
+
f"keys length: {len(keys)}, "
|
|
503
|
+
f"decompressed memory objs length: {len(decompressed_memory_objs)}"
|
|
504
|
+
)
|
|
505
|
+
return decompressed_memory_objs
|
|
506
|
+
|
|
507
|
+
async def support_batched_async_contains(self) -> bool:
|
|
508
|
+
return (
|
|
509
|
+
self.connection is not None
|
|
510
|
+
and self.connection.support_batched_async_contains()
|
|
511
|
+
)
|
|
512
|
+
|
|
513
|
+
async def batched_async_contains(
|
|
514
|
+
self,
|
|
515
|
+
lookup_id: str,
|
|
516
|
+
keys: list[CacheEngineKey],
|
|
517
|
+
pin: bool = False,
|
|
518
|
+
) -> int:
|
|
519
|
+
if self.connection is None:
|
|
520
|
+
logger.warning("Connection is None in batched_async_contains, returning 0")
|
|
521
|
+
return 0
|
|
522
|
+
if self._mla_worker_id_as0_mode:
|
|
523
|
+
keys = [key.with_new_worker_id(0) for key in keys]
|
|
524
|
+
|
|
525
|
+
try:
|
|
526
|
+
assert self.connection.support_batched_async_contains(), (
|
|
527
|
+
f"Connector {self.connection} does not support batched async contains"
|
|
528
|
+
)
|
|
529
|
+
# warning, this timeout will not actually stop the
|
|
530
|
+
# scheduler from waiting for the result
|
|
531
|
+
return await asyncio.wait_for(
|
|
532
|
+
self.connection.batched_async_contains(lookup_id, keys, pin),
|
|
533
|
+
self.config.blocking_timeout_secs,
|
|
534
|
+
)
|
|
535
|
+
except asyncio.TimeoutError:
|
|
536
|
+
logger.warning("batched_async_contains timed out")
|
|
537
|
+
return 0
|
|
538
|
+
except Exception as e:
|
|
539
|
+
logger.warning(f"Error occurred in batched_async_contains: {e}")
|
|
540
|
+
return 0
|
|
541
|
+
|
|
542
|
+
async def support_batched_get_non_blocking(self) -> bool:
|
|
543
|
+
return (
|
|
544
|
+
self.connection is not None
|
|
545
|
+
and self.connection.support_batched_get_non_blocking()
|
|
546
|
+
)
|
|
547
|
+
|
|
548
|
+
async def batched_get_non_blocking(
|
|
549
|
+
self,
|
|
550
|
+
lookup_id: str,
|
|
551
|
+
keys: List[CacheEngineKey],
|
|
552
|
+
transfer_spec: Any = None,
|
|
553
|
+
) -> List[MemoryObj]:
|
|
554
|
+
# Check if local_cpu_backend is available (required for memory allocation)
|
|
555
|
+
if self.local_cpu_backend is None:
|
|
556
|
+
logger.warning(
|
|
557
|
+
"local_cpu_backend is None in batched_get_non_blocking "
|
|
558
|
+
"(likely scheduler role), returning empty list"
|
|
559
|
+
)
|
|
560
|
+
return []
|
|
561
|
+
|
|
562
|
+
if self.connection is None:
|
|
563
|
+
logger.warning(
|
|
564
|
+
"Connection is None in batched_get_non_blocking, returning empty list"
|
|
565
|
+
)
|
|
566
|
+
return []
|
|
567
|
+
try:
|
|
568
|
+
# warning, this timeout will not actually stop the
|
|
569
|
+
# scheduler from waiting for the result
|
|
570
|
+
return await asyncio.wait_for(
|
|
571
|
+
self.connection.batched_get_non_blocking(lookup_id, keys),
|
|
572
|
+
self.config.blocking_timeout_secs,
|
|
573
|
+
)
|
|
574
|
+
except asyncio.TimeoutError:
|
|
575
|
+
logger.warning("batched_get_non_blocking timed out")
|
|
576
|
+
return []
|
|
577
|
+
except Exception as e:
|
|
578
|
+
logger.warning(f"Error occurred in batched_get_non_blocking: {e}")
|
|
579
|
+
return []
|
|
580
|
+
|
|
581
|
+
def pin(self, key: CacheEngineKey) -> bool:
|
|
582
|
+
logger.debug(
|
|
583
|
+
"Remote backend does not support pin. "
|
|
584
|
+
"This method is a no-op and will return True."
|
|
585
|
+
)
|
|
586
|
+
return True
|
|
587
|
+
|
|
588
|
+
def unpin(self, key: CacheEngineKey) -> bool:
|
|
589
|
+
logger.debug(
|
|
590
|
+
"Remote backend does not support unpin. "
|
|
591
|
+
"This method is a no-op and will return True."
|
|
592
|
+
)
|
|
593
|
+
return True
|
|
594
|
+
|
|
595
|
+
def remove(self, key, force=True):
|
|
596
|
+
if self.connection is None:
|
|
597
|
+
logger.warning("Connection is None in remove, returning False")
|
|
598
|
+
return False
|
|
599
|
+
|
|
600
|
+
try:
|
|
601
|
+
return self.connection.remove_sync(key)
|
|
602
|
+
except Exception as e:
|
|
603
|
+
logger.exception(
|
|
604
|
+
f"Failed to remove key {key} from remote backend, error: {e}"
|
|
605
|
+
)
|
|
606
|
+
return False
|
|
607
|
+
|
|
608
|
+
def get_allocator_backend(self):
|
|
609
|
+
assert self.local_cpu_backend is not None, (
|
|
610
|
+
"local_cpu_backend is required for get_allocator_backend, "
|
|
611
|
+
"should not be called in scheduler role"
|
|
612
|
+
)
|
|
613
|
+
return self.local_cpu_backend
|
|
614
|
+
|
|
615
|
+
def close(self):
|
|
616
|
+
try:
|
|
617
|
+
assert self.connection is not None
|
|
618
|
+
future = asyncio.run_coroutine_threadsafe(
|
|
619
|
+
self.connection.close(), self.loop
|
|
620
|
+
)
|
|
621
|
+
future.result()
|
|
622
|
+
logger.info("Remote backend closed.")
|
|
623
|
+
except Exception as e:
|
|
624
|
+
logger.warning(f"Error occurred when closing remote connection: {e}")
|