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,439 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
# Standard
|
|
3
|
+
from typing import TYPE_CHECKING, Any
|
|
4
|
+
|
|
5
|
+
# First Party
|
|
6
|
+
from lmcache.logging import init_logger
|
|
7
|
+
from lmcache.v1.cache_controller.controllers.full_sync_tracker import FullSyncTracker
|
|
8
|
+
from lmcache.v1.cache_controller.message import (
|
|
9
|
+
BatchedKVOperationMsg,
|
|
10
|
+
BatchedP2PLookupMsg,
|
|
11
|
+
BatchedP2PLookupRetMsg,
|
|
12
|
+
CheckFinishMsg,
|
|
13
|
+
CheckFinishRetMsg,
|
|
14
|
+
ClearMsg,
|
|
15
|
+
ClearRetMsg,
|
|
16
|
+
CompressMsg,
|
|
17
|
+
CompressRetMsg,
|
|
18
|
+
DecompressMsg,
|
|
19
|
+
DecompressRetMsg,
|
|
20
|
+
FullSyncBatchMsg,
|
|
21
|
+
FullSyncEndMsg,
|
|
22
|
+
FullSyncStartMsg,
|
|
23
|
+
FullSyncStartRetMsg,
|
|
24
|
+
FullSyncStatusMsg,
|
|
25
|
+
FullSyncStatusRetMsg,
|
|
26
|
+
KVOpEvent,
|
|
27
|
+
LookupMsg,
|
|
28
|
+
LookupRetMsg,
|
|
29
|
+
MoveMsg,
|
|
30
|
+
MoveRetMsg,
|
|
31
|
+
OpType,
|
|
32
|
+
PinMsg,
|
|
33
|
+
PinRetMsg,
|
|
34
|
+
)
|
|
35
|
+
from lmcache.v1.cache_controller.observability import PrometheusLogger
|
|
36
|
+
from lmcache.v1.cache_controller.utils import RegistryTree
|
|
37
|
+
from lmcache.v1.token_database import ChunkedTokenDatabase
|
|
38
|
+
|
|
39
|
+
if TYPE_CHECKING:
|
|
40
|
+
# First Party
|
|
41
|
+
from lmcache.v1.cache_controller.controllers import RegistrationController
|
|
42
|
+
|
|
43
|
+
logger = init_logger(__name__)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
"""
|
|
47
|
+
The kv controller use `(instance_id, worker_id)` -> [location -> set[chunk_hash]]
|
|
48
|
+
as kv_pool. When the the number of instance is small and stable, the time complexity
|
|
49
|
+
of `lookup` in kv controller is O(n). If the number of instance is large or unknown,
|
|
50
|
+
the time complexity will degrade to O(n^2), and the ReverseIndexKVController is a
|
|
51
|
+
better choice.
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class KVController:
|
|
56
|
+
def __init__(
|
|
57
|
+
self,
|
|
58
|
+
registry: RegistryTree,
|
|
59
|
+
full_sync_completion_threshold: float = 0.8,
|
|
60
|
+
full_sync_timeout_s: float = 300.0,
|
|
61
|
+
) -> None:
|
|
62
|
+
# TODO(Jiayi): remove this hardcode
|
|
63
|
+
self.token_database = ChunkedTokenDatabase()
|
|
64
|
+
self.registry = registry
|
|
65
|
+
self.cluster_executor: Any = None
|
|
66
|
+
|
|
67
|
+
# Full sync tracker
|
|
68
|
+
self.full_sync_tracker = FullSyncTracker(
|
|
69
|
+
registry_tree=registry,
|
|
70
|
+
completion_threshold=full_sync_completion_threshold,
|
|
71
|
+
sync_timeout_s=full_sync_timeout_s,
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
def _setup_metrics(self) -> None:
|
|
75
|
+
prometheus_logger = PrometheusLogger.GetInstanceOrNone()
|
|
76
|
+
if prometheus_logger is not None:
|
|
77
|
+
prometheus_logger.kv_pool_keys_count.set_function(
|
|
78
|
+
self.registry.get_total_kv_count
|
|
79
|
+
)
|
|
80
|
+
prometheus_logger.kv_op_seq_discontinuity_count.set_function(
|
|
81
|
+
self.registry.get_seq_discontinuity_count
|
|
82
|
+
)
|
|
83
|
+
# Full sync metrics
|
|
84
|
+
prometheus_logger.full_sync_workers_syncing.set_function(
|
|
85
|
+
self.full_sync_tracker.get_syncing_count
|
|
86
|
+
)
|
|
87
|
+
prometheus_logger.full_sync_workers_completed.set_function(
|
|
88
|
+
self.full_sync_tracker.get_completed_count
|
|
89
|
+
)
|
|
90
|
+
prometheus_logger.full_sync_global_progress.set_function(
|
|
91
|
+
self.full_sync_tracker.get_global_progress
|
|
92
|
+
)
|
|
93
|
+
prometheus_logger.full_sync_missing_batches_total.set_function(
|
|
94
|
+
self.full_sync_tracker.get_total_missing_batches_count
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
def post_init(
|
|
98
|
+
self, reg_controller: "RegistrationController", cluster_executor: Any
|
|
99
|
+
) -> None:
|
|
100
|
+
"""
|
|
101
|
+
Post initialization of the KV controller.
|
|
102
|
+
"""
|
|
103
|
+
self.reg_controller = reg_controller
|
|
104
|
+
self.cluster_executor = cluster_executor
|
|
105
|
+
self._setup_metrics()
|
|
106
|
+
|
|
107
|
+
async def clear(self, msg: ClearMsg) -> ClearRetMsg:
|
|
108
|
+
"""
|
|
109
|
+
Clear kv chunks of instance-worker(s).
|
|
110
|
+
"""
|
|
111
|
+
assert self.cluster_executor is not None
|
|
112
|
+
return await self.cluster_executor.execute("clear", msg)
|
|
113
|
+
|
|
114
|
+
async def pin(self, msg: PinMsg) -> PinRetMsg:
|
|
115
|
+
"""
|
|
116
|
+
Pin kv chunks of instance-worker(s).
|
|
117
|
+
"""
|
|
118
|
+
assert self.cluster_executor is not None
|
|
119
|
+
return await self.cluster_executor.execute("pin", msg)
|
|
120
|
+
|
|
121
|
+
async def compress(self, msg: CompressMsg) -> CompressRetMsg:
|
|
122
|
+
"""
|
|
123
|
+
Compress kv chunks of instance-worker(s).
|
|
124
|
+
"""
|
|
125
|
+
assert self.cluster_executor is not None
|
|
126
|
+
return await self.cluster_executor.execute("compress", msg)
|
|
127
|
+
|
|
128
|
+
async def decompress(self, msg: DecompressMsg) -> DecompressRetMsg:
|
|
129
|
+
"""
|
|
130
|
+
Decompress kv chunks of instance-worker(s).
|
|
131
|
+
"""
|
|
132
|
+
assert self.cluster_executor is not None
|
|
133
|
+
return await self.cluster_executor.execute("decompress", msg)
|
|
134
|
+
|
|
135
|
+
async def move(self, msg: MoveMsg) -> MoveRetMsg:
|
|
136
|
+
"""
|
|
137
|
+
Move kv chunks of instance-worker(s).
|
|
138
|
+
"""
|
|
139
|
+
assert self.cluster_executor is not None
|
|
140
|
+
return await self.cluster_executor.execute("move", msg)
|
|
141
|
+
|
|
142
|
+
async def check_finish(self, msg: CheckFinishMsg) -> CheckFinishRetMsg:
|
|
143
|
+
"""
|
|
144
|
+
Check if an event is finished.
|
|
145
|
+
"""
|
|
146
|
+
assert self.cluster_executor is not None
|
|
147
|
+
return await self.cluster_executor.execute("check_finish", msg)
|
|
148
|
+
|
|
149
|
+
async def handle_batched_kv_operations(self, msg: BatchedKVOperationMsg) -> None:
|
|
150
|
+
"""Handle batched KV operations by forwarding to registry."""
|
|
151
|
+
if not msg.operations:
|
|
152
|
+
return
|
|
153
|
+
|
|
154
|
+
# Check if worker is currently in full sync
|
|
155
|
+
if self.full_sync_tracker.is_worker_syncing(msg.instance_id, msg.worker_id):
|
|
156
|
+
# During full sync, incremental operations should be discarded
|
|
157
|
+
logger.debug(
|
|
158
|
+
"Discarding incremental KV operations during full sync: "
|
|
159
|
+
"instance=%s, worker=%d, sync_id=%s, operation_count=%d",
|
|
160
|
+
msg.instance_id,
|
|
161
|
+
msg.worker_id,
|
|
162
|
+
self.full_sync_tracker.get_sync_id(msg.instance_id, msg.worker_id),
|
|
163
|
+
len(msg.operations),
|
|
164
|
+
)
|
|
165
|
+
return
|
|
166
|
+
|
|
167
|
+
if not self.registry.handle_batched_kv_operations(msg):
|
|
168
|
+
logger.warning(
|
|
169
|
+
"Failed to handle batched KV operations, instance: %s, worker: %d",
|
|
170
|
+
msg.instance_id,
|
|
171
|
+
msg.worker_id,
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
# ============= Full Sync Message Handlers =============
|
|
175
|
+
|
|
176
|
+
async def handle_full_sync_start(
|
|
177
|
+
self, msg: FullSyncStartMsg
|
|
178
|
+
) -> FullSyncStartRetMsg:
|
|
179
|
+
"""
|
|
180
|
+
Handle full sync start request from a worker.
|
|
181
|
+
|
|
182
|
+
This is called when a worker wants to start full sync.
|
|
183
|
+
The controller should:
|
|
184
|
+
1. Clear existing keys for this worker
|
|
185
|
+
2. Mark the worker as syncing (incremental events will be discarded)
|
|
186
|
+
3. Return acceptance
|
|
187
|
+
"""
|
|
188
|
+
instance_id = msg.instance_id
|
|
189
|
+
worker_id = msg.worker_id
|
|
190
|
+
sync_id = msg.sync_id
|
|
191
|
+
report_id = (instance_id, worker_id)
|
|
192
|
+
|
|
193
|
+
# Start sync tracking first (mark worker as SYNCING)
|
|
194
|
+
success = self.full_sync_tracker.start_sync(
|
|
195
|
+
instance_id=instance_id,
|
|
196
|
+
worker_id=worker_id,
|
|
197
|
+
sync_id=sync_id,
|
|
198
|
+
total_keys=msg.total_keys,
|
|
199
|
+
batch_count=msg.batch_count,
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
if not success:
|
|
203
|
+
logger.warning(
|
|
204
|
+
"Failed to start sync for worker %s: sync_id=%s", report_id, sync_id
|
|
205
|
+
)
|
|
206
|
+
return FullSyncStartRetMsg(
|
|
207
|
+
sync_id=sync_id,
|
|
208
|
+
accepted=False,
|
|
209
|
+
error_msg="Failed to start sync: worker already syncing with "
|
|
210
|
+
"different sync_id or worker not found",
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
# Now clear existing keys for this worker/location using efficient batch method
|
|
214
|
+
# This prevents new incremental messages from being processed while we clear
|
|
215
|
+
existing_keys = self.registry.get_worker_kv_keys(
|
|
216
|
+
instance_id, worker_id, msg.location
|
|
217
|
+
)
|
|
218
|
+
if existing_keys:
|
|
219
|
+
old_count = len(existing_keys)
|
|
220
|
+
# Use efficient batch clear method
|
|
221
|
+
cleared = self.registry.clear_worker_kv(
|
|
222
|
+
instance_id, worker_id, msg.location
|
|
223
|
+
)
|
|
224
|
+
if cleared:
|
|
225
|
+
logger.info(
|
|
226
|
+
"Cleared %d existing keys for worker %s location %s "
|
|
227
|
+
"before full sync",
|
|
228
|
+
old_count,
|
|
229
|
+
report_id,
|
|
230
|
+
msg.location,
|
|
231
|
+
)
|
|
232
|
+
else:
|
|
233
|
+
logger.warning(
|
|
234
|
+
"Failed to clear keys for worker %s location %s",
|
|
235
|
+
report_id,
|
|
236
|
+
msg.location,
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
logger.info(
|
|
240
|
+
"Accepted full sync start: worker=%s, sync_id=%s, "
|
|
241
|
+
"total_keys=%d, batch_count=%d",
|
|
242
|
+
report_id,
|
|
243
|
+
sync_id,
|
|
244
|
+
msg.total_keys,
|
|
245
|
+
msg.batch_count,
|
|
246
|
+
)
|
|
247
|
+
return FullSyncStartRetMsg(sync_id=sync_id, accepted=True)
|
|
248
|
+
|
|
249
|
+
async def handle_full_sync_batch(self, msg: FullSyncBatchMsg) -> None:
|
|
250
|
+
"""
|
|
251
|
+
Handle full sync batch message from a worker.
|
|
252
|
+
|
|
253
|
+
This adds the keys from the batch to the registry.
|
|
254
|
+
"""
|
|
255
|
+
instance_id = msg.instance_id
|
|
256
|
+
worker_id = msg.worker_id
|
|
257
|
+
location = msg.location
|
|
258
|
+
sync_id = msg.sync_id
|
|
259
|
+
batch_id = msg.batch_id
|
|
260
|
+
keys = msg.keys
|
|
261
|
+
report_id = (instance_id, worker_id)
|
|
262
|
+
|
|
263
|
+
# Record batch receipt
|
|
264
|
+
if not self.full_sync_tracker.receive_batch(
|
|
265
|
+
instance_id=instance_id,
|
|
266
|
+
worker_id=worker_id,
|
|
267
|
+
sync_id=sync_id,
|
|
268
|
+
batch_id=batch_id,
|
|
269
|
+
keys_count=len(keys),
|
|
270
|
+
):
|
|
271
|
+
logger.warning(
|
|
272
|
+
"Failed to record batch %d for worker %s", batch_id, report_id
|
|
273
|
+
)
|
|
274
|
+
return
|
|
275
|
+
|
|
276
|
+
# Add keys to registry using batched operations
|
|
277
|
+
operations = []
|
|
278
|
+
for seq_num, key in enumerate(keys):
|
|
279
|
+
operations.append(
|
|
280
|
+
KVOpEvent(
|
|
281
|
+
op_type=OpType.ADMIT,
|
|
282
|
+
key=key,
|
|
283
|
+
seq_num=seq_num,
|
|
284
|
+
)
|
|
285
|
+
)
|
|
286
|
+
if operations:
|
|
287
|
+
batch_msg = BatchedKVOperationMsg(
|
|
288
|
+
instance_id=instance_id,
|
|
289
|
+
worker_id=worker_id,
|
|
290
|
+
location=location,
|
|
291
|
+
operations=operations,
|
|
292
|
+
)
|
|
293
|
+
self.registry.handle_batched_kv_operations(batch_msg, is_full_sync=True)
|
|
294
|
+
|
|
295
|
+
current_keys = self.registry.get_worker_kv_keys(
|
|
296
|
+
instance_id, worker_id, location
|
|
297
|
+
)
|
|
298
|
+
logger.debug(
|
|
299
|
+
"Added %d keys from batch %d for worker %s, total now: %d",
|
|
300
|
+
len(keys),
|
|
301
|
+
batch_id,
|
|
302
|
+
report_id,
|
|
303
|
+
len(current_keys),
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
async def handle_full_sync_end(self, msg: FullSyncEndMsg) -> None:
|
|
307
|
+
"""
|
|
308
|
+
Handle full sync end message from a worker.
|
|
309
|
+
|
|
310
|
+
This marks the sync as end-received and records actual total keys.
|
|
311
|
+
"""
|
|
312
|
+
instance_id = msg.instance_id
|
|
313
|
+
worker_id = msg.worker_id
|
|
314
|
+
sync_id = msg.sync_id
|
|
315
|
+
actual_total_keys = msg.actual_total_keys
|
|
316
|
+
report_id = (instance_id, worker_id)
|
|
317
|
+
|
|
318
|
+
success = self.full_sync_tracker.complete_sync(
|
|
319
|
+
instance_id=instance_id,
|
|
320
|
+
worker_id=worker_id,
|
|
321
|
+
sync_id=sync_id,
|
|
322
|
+
actual_total_keys=actual_total_keys,
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
if success:
|
|
326
|
+
# Verify registry has the expected number of keys
|
|
327
|
+
actual_keys_in_pool = len(
|
|
328
|
+
self.registry.get_worker_kv_keys(instance_id, worker_id, msg.location)
|
|
329
|
+
)
|
|
330
|
+
logger.info(
|
|
331
|
+
"Full sync completed for worker %s: sync_id=%s, "
|
|
332
|
+
"reported_keys=%d, keys_in_pool=%d",
|
|
333
|
+
report_id,
|
|
334
|
+
sync_id,
|
|
335
|
+
actual_total_keys,
|
|
336
|
+
actual_keys_in_pool,
|
|
337
|
+
)
|
|
338
|
+
else:
|
|
339
|
+
logger.warning(
|
|
340
|
+
"Failed to complete full sync for worker %s: sync_id=%s",
|
|
341
|
+
report_id,
|
|
342
|
+
sync_id,
|
|
343
|
+
)
|
|
344
|
+
|
|
345
|
+
async def handle_full_sync_status(
|
|
346
|
+
self, msg: FullSyncStatusMsg
|
|
347
|
+
) -> FullSyncStatusRetMsg:
|
|
348
|
+
"""
|
|
349
|
+
Handle full sync status query from a worker.
|
|
350
|
+
|
|
351
|
+
Returns the sync status including any missing batches that need resending.
|
|
352
|
+
"""
|
|
353
|
+
is_complete, global_progress, can_exit_freeze, missing_batches = (
|
|
354
|
+
self.full_sync_tracker.get_sync_status(
|
|
355
|
+
instance_id=msg.instance_id,
|
|
356
|
+
worker_id=msg.worker_id,
|
|
357
|
+
sync_id=msg.sync_id,
|
|
358
|
+
)
|
|
359
|
+
)
|
|
360
|
+
|
|
361
|
+
if missing_batches:
|
|
362
|
+
logger.info(
|
|
363
|
+
"Full sync status query: worker=(%s, %d), sync_id=%s, "
|
|
364
|
+
"is_complete=%s, missing_batches=%s",
|
|
365
|
+
msg.instance_id,
|
|
366
|
+
msg.worker_id,
|
|
367
|
+
msg.sync_id,
|
|
368
|
+
is_complete,
|
|
369
|
+
missing_batches,
|
|
370
|
+
)
|
|
371
|
+
|
|
372
|
+
return FullSyncStatusRetMsg(
|
|
373
|
+
sync_id=msg.sync_id,
|
|
374
|
+
is_complete=is_complete,
|
|
375
|
+
global_progress=global_progress,
|
|
376
|
+
can_exit_freeze=can_exit_freeze,
|
|
377
|
+
missing_batches=missing_batches,
|
|
378
|
+
)
|
|
379
|
+
|
|
380
|
+
# TODO(Jiayi): The current implementation does not handle
|
|
381
|
+
# the case where the prefix chunks are evicted while the
|
|
382
|
+
# suffix chunk is still in the system. LMCache should guarantee
|
|
383
|
+
# this does not happen.
|
|
384
|
+
# TODO(Jiayi): The current implementation does not consider
|
|
385
|
+
# the location of the kv chunks. It simply returns the
|
|
386
|
+
# `instance_id` with longest prefix.
|
|
387
|
+
# TODO(Jiayi): Need to get rid of the hash somehow
|
|
388
|
+
async def lookup(self, msg: LookupMsg) -> LookupRetMsg:
|
|
389
|
+
tokens = msg.tokens
|
|
390
|
+
layout_info = {}
|
|
391
|
+
for start, end, key in self.token_database.process_tokens(
|
|
392
|
+
tokens, make_key=False
|
|
393
|
+
):
|
|
394
|
+
result = self.registry.find_kv(key)
|
|
395
|
+
if result is None:
|
|
396
|
+
break
|
|
397
|
+
matched_instance = result.instance_id
|
|
398
|
+
matched_location = result.location
|
|
399
|
+
layout_info[matched_instance] = (matched_location, end)
|
|
400
|
+
return LookupRetMsg(layout_info=layout_info, event_id=msg.event_id)
|
|
401
|
+
|
|
402
|
+
# TODO: improve the matching logic, return multi results
|
|
403
|
+
async def batched_p2p_lookup(
|
|
404
|
+
self, msg: BatchedP2PLookupMsg
|
|
405
|
+
) -> BatchedP2PLookupRetMsg:
|
|
406
|
+
"""
|
|
407
|
+
Perform batched P2P lookup for multiple keys.
|
|
408
|
+
|
|
409
|
+
:param BatchedP2PLookupMsg msg: The batched P2P lookup message containing keys.
|
|
410
|
+
|
|
411
|
+
:return: A BatchedP2PLookupRetMsg containing the lookup results.
|
|
412
|
+
"""
|
|
413
|
+
hashes = msg.hashes
|
|
414
|
+
if not hashes:
|
|
415
|
+
return BatchedP2PLookupRetMsg(layout_info=[("", "", 0, "")])
|
|
416
|
+
|
|
417
|
+
# Single lookup to get all needed info (optimized path)
|
|
418
|
+
result = self.registry.find_kv_with_worker_info(
|
|
419
|
+
hashes[0], exclude_instance_id=msg.instance_id
|
|
420
|
+
)
|
|
421
|
+
if result is None:
|
|
422
|
+
return BatchedP2PLookupRetMsg(layout_info=[("", "", 0, "")])
|
|
423
|
+
|
|
424
|
+
kv_info, peer_init_url, current_keys = result
|
|
425
|
+
if peer_init_url is None:
|
|
426
|
+
return BatchedP2PLookupRetMsg(layout_info=[("", "", 0, "")])
|
|
427
|
+
|
|
428
|
+
# Count hits efficiently
|
|
429
|
+
num_hit_chunks = 0
|
|
430
|
+
for key in hashes:
|
|
431
|
+
if key not in current_keys:
|
|
432
|
+
break
|
|
433
|
+
num_hit_chunks += 1
|
|
434
|
+
|
|
435
|
+
return BatchedP2PLookupRetMsg(
|
|
436
|
+
layout_info=[
|
|
437
|
+
(kv_info.instance_id, kv_info.location, num_hit_chunks, peer_init_url),
|
|
438
|
+
]
|
|
439
|
+
)
|