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,320 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
# Standard
|
|
3
|
+
from threading import Lock
|
|
4
|
+
from typing import Dict, Optional
|
|
5
|
+
import abc
|
|
6
|
+
import asyncio
|
|
7
|
+
import functools
|
|
8
|
+
import hashlib
|
|
9
|
+
import logging
|
|
10
|
+
import time
|
|
11
|
+
|
|
12
|
+
# First Party
|
|
13
|
+
from lmcache.utils import CacheEngineKey
|
|
14
|
+
from lmcache.v1.config import LMCacheEngineConfig
|
|
15
|
+
from lmcache.v1.memory_management import MemoryObj
|
|
16
|
+
from lmcache.v1.storage_backend.connector.base_connector import RemoteConnector
|
|
17
|
+
|
|
18
|
+
logger = logging.getLogger(__name__)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class AuditConnectorMeta(abc.ABCMeta):
|
|
22
|
+
"""Metaclass that dynamically generates wrapper methods for all
|
|
23
|
+
RemoteConnector methods
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
def __new__(mcs, name, bases, namespace):
|
|
27
|
+
# Get all methods from RemoteConnector including abstract methods
|
|
28
|
+
# We need to check both the class dict and inherited methods
|
|
29
|
+
all_methods = {}
|
|
30
|
+
|
|
31
|
+
# Collect methods from RemoteConnector and its bases
|
|
32
|
+
for base in RemoteConnector.__mro__:
|
|
33
|
+
for method_name, method_obj in base.__dict__.items():
|
|
34
|
+
if method_name not in all_methods and callable(method_obj):
|
|
35
|
+
all_methods[method_name] = method_obj
|
|
36
|
+
|
|
37
|
+
for method_name, method in all_methods.items():
|
|
38
|
+
# Skip private methods and methods already defined in namespace
|
|
39
|
+
if method_name.startswith("_") or method_name in namespace:
|
|
40
|
+
continue
|
|
41
|
+
|
|
42
|
+
# Skip class methods, static methods, and properties
|
|
43
|
+
if isinstance(method, (classmethod, staticmethod, property)):
|
|
44
|
+
continue
|
|
45
|
+
|
|
46
|
+
# Check if method is marked with @NotAudit
|
|
47
|
+
is_not_audit = getattr(method, "_not_audit", False)
|
|
48
|
+
|
|
49
|
+
# Determine if method is async
|
|
50
|
+
is_async = asyncio.iscoroutinefunction(method)
|
|
51
|
+
|
|
52
|
+
# Create appropriate wrapper and add to namespace
|
|
53
|
+
if is_not_audit:
|
|
54
|
+
if is_async:
|
|
55
|
+
namespace[method_name] = mcs._create_passthrough_async_method(
|
|
56
|
+
method_name, method
|
|
57
|
+
)
|
|
58
|
+
else:
|
|
59
|
+
namespace[method_name] = mcs._create_passthrough_sync_method(
|
|
60
|
+
method_name, method
|
|
61
|
+
)
|
|
62
|
+
else:
|
|
63
|
+
if is_async:
|
|
64
|
+
namespace[method_name] = mcs._create_audit_async_method(
|
|
65
|
+
method_name, method
|
|
66
|
+
)
|
|
67
|
+
else:
|
|
68
|
+
namespace[method_name] = mcs._create_audit_sync_method(
|
|
69
|
+
method_name, method
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
# Create the class with all methods in namespace
|
|
73
|
+
cls = super().__new__(mcs, name, bases, namespace)
|
|
74
|
+
|
|
75
|
+
# Clear abstract methods since we've implemented them all via wrappers
|
|
76
|
+
# The wrappers delegate to real_connector which has the actual implementations
|
|
77
|
+
if hasattr(cls, "__abstractmethods__"):
|
|
78
|
+
cls.__abstractmethods__ = frozenset()
|
|
79
|
+
|
|
80
|
+
return cls
|
|
81
|
+
|
|
82
|
+
@staticmethod
|
|
83
|
+
def _create_passthrough_async_method(method_name: str, original_method):
|
|
84
|
+
"""Create a pass-through async method without logging"""
|
|
85
|
+
|
|
86
|
+
@functools.wraps(original_method)
|
|
87
|
+
async def wrapper(self, *args, **kwargs):
|
|
88
|
+
real_method = getattr(self.real_connector, method_name)
|
|
89
|
+
return await real_method(*args, **kwargs)
|
|
90
|
+
|
|
91
|
+
wrapper.__name__ = method_name
|
|
92
|
+
wrapper.__qualname__ = f"AuditConnector.{method_name}"
|
|
93
|
+
return wrapper
|
|
94
|
+
|
|
95
|
+
@staticmethod
|
|
96
|
+
def _create_passthrough_sync_method(method_name: str, original_method):
|
|
97
|
+
"""Create a pass-through sync method without logging"""
|
|
98
|
+
|
|
99
|
+
@functools.wraps(original_method)
|
|
100
|
+
def wrapper(self, *args, **kwargs):
|
|
101
|
+
real_method = getattr(self.real_connector, method_name)
|
|
102
|
+
return real_method(*args, **kwargs)
|
|
103
|
+
|
|
104
|
+
wrapper.__name__ = method_name
|
|
105
|
+
wrapper.__qualname__ = f"AuditConnector.{method_name}"
|
|
106
|
+
return wrapper
|
|
107
|
+
|
|
108
|
+
@staticmethod
|
|
109
|
+
def _create_audit_async_method(method_name: str, original_method):
|
|
110
|
+
"""Create an audit async method with logging"""
|
|
111
|
+
|
|
112
|
+
@functools.wraps(original_method)
|
|
113
|
+
async def wrapper(self, *args, **kwargs):
|
|
114
|
+
# Special handling for put/get methods with checksum
|
|
115
|
+
if method_name == "put":
|
|
116
|
+
return await self._audit_put(*args, **kwargs)
|
|
117
|
+
elif method_name == "get":
|
|
118
|
+
return await self._audit_get(*args, **kwargs)
|
|
119
|
+
|
|
120
|
+
# Check if method is in excluded commands
|
|
121
|
+
if hasattr(self, "excluded_cmds") and method_name in self.excluded_cmds:
|
|
122
|
+
real_method = getattr(self.real_connector, method_name)
|
|
123
|
+
return await real_method(*args, **kwargs)
|
|
124
|
+
|
|
125
|
+
# Generic audit logging
|
|
126
|
+
self.logger.debug(
|
|
127
|
+
f"[REMOTE_AUDIT][{self.real_connector}]:{method_name.upper()}|START"
|
|
128
|
+
)
|
|
129
|
+
t1 = time.perf_counter()
|
|
130
|
+
try:
|
|
131
|
+
real_method = getattr(self.real_connector, method_name)
|
|
132
|
+
result = await real_method(*args, **kwargs)
|
|
133
|
+
t2 = time.perf_counter()
|
|
134
|
+
cost = (t2 - t1) * 1000
|
|
135
|
+
self.logger.info(
|
|
136
|
+
f"[REMOTE_AUDIT][{self.real_connector}]:{method_name.upper()}|"
|
|
137
|
+
f"SUCCESS|Cost:{cost:.6f}ms"
|
|
138
|
+
)
|
|
139
|
+
return result
|
|
140
|
+
except Exception as e:
|
|
141
|
+
self.logger.error(
|
|
142
|
+
f"[REMOTE_AUDIT][{self.real_connector}]:{method_name.upper()}|"
|
|
143
|
+
f"FAILED|Error: {str(e)}"
|
|
144
|
+
)
|
|
145
|
+
raise
|
|
146
|
+
|
|
147
|
+
wrapper.__name__ = method_name
|
|
148
|
+
wrapper.__qualname__ = f"AuditConnector.{method_name}"
|
|
149
|
+
return wrapper
|
|
150
|
+
|
|
151
|
+
@staticmethod
|
|
152
|
+
def _create_audit_sync_method(method_name: str, original_method):
|
|
153
|
+
"""Create an audit sync method with logging"""
|
|
154
|
+
|
|
155
|
+
@functools.wraps(original_method)
|
|
156
|
+
def wrapper(self, *args, **kwargs):
|
|
157
|
+
# Check if method is in excluded commands
|
|
158
|
+
if hasattr(self, "excluded_cmds") and method_name in self.excluded_cmds:
|
|
159
|
+
real_method = getattr(self.real_connector, method_name)
|
|
160
|
+
return real_method(*args, **kwargs)
|
|
161
|
+
|
|
162
|
+
self.logger.debug(
|
|
163
|
+
f"[REMOTE_AUDIT][{self.real_connector}]:{method_name.upper()}|START"
|
|
164
|
+
)
|
|
165
|
+
t1 = time.perf_counter()
|
|
166
|
+
try:
|
|
167
|
+
real_method = getattr(self.real_connector, method_name)
|
|
168
|
+
result = real_method(*args, **kwargs)
|
|
169
|
+
t2 = time.perf_counter()
|
|
170
|
+
cost = (t2 - t1) * 1000
|
|
171
|
+
self.logger.info(
|
|
172
|
+
f"[REMOTE_AUDIT][{self.real_connector}]:{method_name.upper()}|"
|
|
173
|
+
f"SUCCESS|Cost:{cost:.6f}ms"
|
|
174
|
+
)
|
|
175
|
+
return result
|
|
176
|
+
except Exception as e:
|
|
177
|
+
self.logger.error(
|
|
178
|
+
f"[REMOTE_AUDIT][{self.real_connector}]:{method_name.upper()}|"
|
|
179
|
+
f"FAILED|Error: {str(e)}"
|
|
180
|
+
)
|
|
181
|
+
raise
|
|
182
|
+
|
|
183
|
+
wrapper.__name__ = method_name
|
|
184
|
+
wrapper.__qualname__ = f"AuditConnector.{method_name}"
|
|
185
|
+
return wrapper
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
class AuditConnector(RemoteConnector, metaclass=AuditConnectorMeta):
|
|
189
|
+
"""Audit wrapper for RemoteConnector that dynamically wraps all methods.
|
|
190
|
+
|
|
191
|
+
Features:
|
|
192
|
+
- Automatically wraps all RemoteConnector methods
|
|
193
|
+
- Methods marked with @NotAudit are forwarded without logging
|
|
194
|
+
- Configurable checksum verification via URL parameter
|
|
195
|
+
- Logs all operations with timestamps
|
|
196
|
+
- Optional checksum validation for put/get operations
|
|
197
|
+
"""
|
|
198
|
+
|
|
199
|
+
def __init__(
|
|
200
|
+
self, real_connector: RemoteConnector, lmcache_config: LMCacheEngineConfig
|
|
201
|
+
):
|
|
202
|
+
self.real_connector = real_connector
|
|
203
|
+
self.verify_checksum = (
|
|
204
|
+
lmcache_config.extra_config is not None
|
|
205
|
+
and "audit_verify_checksum" in lmcache_config.extra_config
|
|
206
|
+
and lmcache_config.extra_config["audit_verify_checksum"]
|
|
207
|
+
)
|
|
208
|
+
self.calc_checksum = (
|
|
209
|
+
lmcache_config.extra_config is not None
|
|
210
|
+
and "audit_calc_checksum" in lmcache_config.extra_config
|
|
211
|
+
and lmcache_config.extra_config["audit_calc_checksum"]
|
|
212
|
+
)
|
|
213
|
+
self.checksum_registry: Dict[CacheEngineKey, str] = {}
|
|
214
|
+
self.registry_lock = Lock() if self.verify_checksum else None
|
|
215
|
+
|
|
216
|
+
# Parse audit exclude commands
|
|
217
|
+
self.excluded_cmds = set()
|
|
218
|
+
if (
|
|
219
|
+
lmcache_config.extra_config
|
|
220
|
+
and "audit_exclude_cmds" in lmcache_config.extra_config
|
|
221
|
+
):
|
|
222
|
+
exclude_cmds = lmcache_config.extra_config["audit_exclude_cmds"]
|
|
223
|
+
if exclude_cmds:
|
|
224
|
+
self.excluded_cmds = {cmd.strip() for cmd in exclude_cmds.split(",")}
|
|
225
|
+
|
|
226
|
+
self.logger = logger.getChild("audit")
|
|
227
|
+
|
|
228
|
+
logger.info(
|
|
229
|
+
f"[REMOTE_AUDIT][{self.real_connector}]:INITIALIZED|"
|
|
230
|
+
f"Calc Checksum:{self.calc_checksum}|"
|
|
231
|
+
f"Verify Checksum: {self.verify_checksum}|"
|
|
232
|
+
f"Excluded Cmds: {self.excluded_cmds}"
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
def _calculate_checksum(self, data: bytes) -> str:
|
|
236
|
+
"""Calculate SHA-256 checksum for data validation"""
|
|
237
|
+
return hashlib.sha256(data).hexdigest()
|
|
238
|
+
|
|
239
|
+
async def _audit_put(self, key: CacheEngineKey, memory_obj: MemoryObj):
|
|
240
|
+
"""Store data with optional checksum tracking"""
|
|
241
|
+
data = memory_obj.byte_array
|
|
242
|
+
checksum = self._calculate_checksum(data) if self.calc_checksum else "N/A"
|
|
243
|
+
data_size = len(data)
|
|
244
|
+
self.logger.debug(
|
|
245
|
+
f"[REMOTE_AUDIT][{self.real_connector}]:PUT|START|Size:{data_size}|"
|
|
246
|
+
f"Checksum:{checksum[:8]}|Saved:{len(self.checksum_registry)}|Key:{key}"
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
try:
|
|
250
|
+
t1 = time.perf_counter()
|
|
251
|
+
await self.real_connector.put(key, memory_obj)
|
|
252
|
+
t2 = time.perf_counter()
|
|
253
|
+
cost = (t2 - t1) * 1000
|
|
254
|
+
if self.registry_lock:
|
|
255
|
+
with self.registry_lock:
|
|
256
|
+
self.checksum_registry[key] = checksum
|
|
257
|
+
self.logger.info(
|
|
258
|
+
f"[REMOTE_AUDIT][{self.real_connector}]:PUT|SUCCESS|Size:{data_size}|"
|
|
259
|
+
f"Checksum:{checksum[:8]}|Cost:{cost:.6f}ms|Saved:"
|
|
260
|
+
f"{len(self.checksum_registry)}|Key:{key}"
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
except Exception as e:
|
|
264
|
+
self.logger.error(
|
|
265
|
+
f"[REMOTE_AUDIT][{self.real_connector}]:PUT|FAILED|Size:{data_size}|"
|
|
266
|
+
f"Key:{key}|Error: {str(e)}"
|
|
267
|
+
)
|
|
268
|
+
raise
|
|
269
|
+
|
|
270
|
+
async def _audit_get(self, key: CacheEngineKey) -> Optional[MemoryObj]:
|
|
271
|
+
"""Retrieve data with optional integrity check"""
|
|
272
|
+
self.logger.debug(
|
|
273
|
+
f"[REMOTE_AUDIT][{self.real_connector}]:GET|START|"
|
|
274
|
+
f"Saved:{len(self.checksum_registry)}|Key:{key}"
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
try:
|
|
278
|
+
t1 = time.perf_counter()
|
|
279
|
+
result = await self.real_connector.get(key)
|
|
280
|
+
t2 = time.perf_counter()
|
|
281
|
+
if result is None:
|
|
282
|
+
self.logger.info(
|
|
283
|
+
f"[REMOTE_AUDIT][{self.real_connector}]:GET|MISS|Key:{key}|"
|
|
284
|
+
f"Saved: {len(self.checksum_registry)}"
|
|
285
|
+
)
|
|
286
|
+
return None
|
|
287
|
+
|
|
288
|
+
current_data = result.byte_array
|
|
289
|
+
current_checksum = (
|
|
290
|
+
self._calculate_checksum(current_data) if self.calc_checksum else "N/A"
|
|
291
|
+
)
|
|
292
|
+
data_size = len(current_data)
|
|
293
|
+
|
|
294
|
+
if self.registry_lock:
|
|
295
|
+
with self.registry_lock:
|
|
296
|
+
expected_checksum = self.checksum_registry.get(key)
|
|
297
|
+
|
|
298
|
+
if expected_checksum and current_checksum != expected_checksum:
|
|
299
|
+
self.logger.error(
|
|
300
|
+
f"[REMOTE_AUDIT][{self.real_connector}]:"
|
|
301
|
+
f"GET|MISMATCH|Size:{data_size}|"
|
|
302
|
+
f"Expected:<{expected_checksum[:8]}>|"
|
|
303
|
+
f"Actual:<{current_checksum[:8]}>|Key:{key}"
|
|
304
|
+
)
|
|
305
|
+
return None
|
|
306
|
+
|
|
307
|
+
cost = (t2 - t1) * 1000
|
|
308
|
+
self.logger.info(
|
|
309
|
+
f"[REMOTE_AUDIT][{self.real_connector}]:GET|SUCCESS|"
|
|
310
|
+
f"Checksum:{current_checksum[:8]}|"
|
|
311
|
+
f"Cost:{cost:.6f}ms|Saved:{len(self.checksum_registry)}|Key:{key}"
|
|
312
|
+
)
|
|
313
|
+
return result
|
|
314
|
+
|
|
315
|
+
except Exception as e:
|
|
316
|
+
self.logger.error(
|
|
317
|
+
f"[REMOTE_AUDIT][{self.real_connector}]:GET|"
|
|
318
|
+
f"FAILED|Key:{key}|Error: {str(e)}"
|
|
319
|
+
)
|
|
320
|
+
raise
|
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
# Standard
|
|
3
|
+
from typing import List, Optional
|
|
4
|
+
import abc
|
|
5
|
+
import asyncio
|
|
6
|
+
|
|
7
|
+
# Third Party
|
|
8
|
+
import torch
|
|
9
|
+
|
|
10
|
+
# First Party
|
|
11
|
+
from lmcache.integration.vllm.utils import get_size_bytes
|
|
12
|
+
from lmcache.logging import init_logger
|
|
13
|
+
from lmcache.utils import CacheEngineKey
|
|
14
|
+
from lmcache.v1.config import LMCacheEngineConfig
|
|
15
|
+
from lmcache.v1.memory_management import MemoryFormat, MemoryObj
|
|
16
|
+
from lmcache.v1.metadata import LMCacheMetadata
|
|
17
|
+
from lmcache.v1.protocol import get_remote_metadata_bytes, init_remote_metadata_info
|
|
18
|
+
|
|
19
|
+
logger = init_logger(__name__)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def NotAudit(func):
|
|
23
|
+
"""
|
|
24
|
+
Decorator to mark methods that should not be audited.
|
|
25
|
+
These methods will be directly forwarded to the real connector without logging.
|
|
26
|
+
"""
|
|
27
|
+
func._not_audit = True
|
|
28
|
+
return func
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class RemoteConnector(metaclass=abc.ABCMeta):
|
|
32
|
+
"""
|
|
33
|
+
Interface for remote connector
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
def __init__(
|
|
37
|
+
self, config: LMCacheEngineConfig, metadata: Optional[LMCacheMetadata]
|
|
38
|
+
):
|
|
39
|
+
"""
|
|
40
|
+
Initialize some common attributes, which will be used in the subclasses.
|
|
41
|
+
- `save_chunk_meta` is a flag to indicate whether to save the chunk meta info.
|
|
42
|
+
- `meta_shapes` is a list of shapes of lmcache full chunk.
|
|
43
|
+
- `meta_dtypes` is a list of dtypes of lmcache chunk.
|
|
44
|
+
- `meta_fmt` is the memory format of the lmcache chunk.
|
|
45
|
+
- `full_chunk_size_bytes` is the size of the lmcache full chunk.
|
|
46
|
+
- `single_token_size` is the size of a single token.`
|
|
47
|
+
- `remote_metadata_bytes` is the size of the remote metadata.
|
|
48
|
+
|
|
49
|
+
Input:
|
|
50
|
+
config: the lmcache engine config
|
|
51
|
+
metadata: the lmcache engine metadata
|
|
52
|
+
"""
|
|
53
|
+
# TODO(chunxiaozheng): support layerwise here
|
|
54
|
+
assert metadata is not None
|
|
55
|
+
self.save_chunk_meta: bool = (
|
|
56
|
+
config.extra_config is None
|
|
57
|
+
or config.extra_config.get("save_chunk_meta", True)
|
|
58
|
+
or config.use_layerwise
|
|
59
|
+
)
|
|
60
|
+
self.meta_shapes: list[torch.Size] = metadata.get_shapes()
|
|
61
|
+
self.meta_dtypes: list[torch.dtype] = metadata.get_dtypes()
|
|
62
|
+
self.meta_fmt: MemoryFormat = (
|
|
63
|
+
MemoryFormat.KV_MLA_FMT if metadata.use_mla else MemoryFormat.KV_2LTD
|
|
64
|
+
)
|
|
65
|
+
self.full_chunk_size_bytes: int = get_size_bytes(
|
|
66
|
+
self.meta_shapes, self.meta_dtypes
|
|
67
|
+
)
|
|
68
|
+
assert self.full_chunk_size_bytes % metadata.chunk_size == 0
|
|
69
|
+
self.single_token_size = self.full_chunk_size_bytes // metadata.chunk_size
|
|
70
|
+
|
|
71
|
+
# init remote metadata info
|
|
72
|
+
init_remote_metadata_info(metadata.get_num_groups())
|
|
73
|
+
self.remote_metadata_bytes = get_remote_metadata_bytes()
|
|
74
|
+
logger.info(
|
|
75
|
+
"init remote connector metadata info, shapes: %s, dtypes: %s, fmt: %s, "
|
|
76
|
+
"full chunk size: %s, single token size: %s, remote metadata bytes: %s",
|
|
77
|
+
self.meta_shapes,
|
|
78
|
+
self.meta_dtypes,
|
|
79
|
+
self.meta_fmt,
|
|
80
|
+
self.full_chunk_size_bytes,
|
|
81
|
+
self.single_token_size,
|
|
82
|
+
self.remote_metadata_bytes,
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
@NotAudit
|
|
86
|
+
def reshape_partial_chunk(
|
|
87
|
+
self,
|
|
88
|
+
memory_obj: MemoryObj,
|
|
89
|
+
bytes_read: int,
|
|
90
|
+
) -> MemoryObj:
|
|
91
|
+
assert self.full_chunk_size_bytes is not None
|
|
92
|
+
assert self.single_token_size is not None
|
|
93
|
+
if (
|
|
94
|
+
bytes_read == 0
|
|
95
|
+
or bytes_read % self.single_token_size != 0
|
|
96
|
+
or bytes_read > self.full_chunk_size_bytes
|
|
97
|
+
):
|
|
98
|
+
raise ValueError(
|
|
99
|
+
f"bytes_read: {bytes_read} is illegal, "
|
|
100
|
+
f"single_token_size: {self.single_token_size}, "
|
|
101
|
+
f"full_chunk_size_bytes: {self.full_chunk_size_bytes}"
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
if bytes_read == self.full_chunk_size_bytes:
|
|
105
|
+
# full chunk, return directly
|
|
106
|
+
return memory_obj
|
|
107
|
+
|
|
108
|
+
# NOTE: for unfull chunk, we have no way to verify
|
|
109
|
+
shape_list = list(memory_obj.meta.shape)
|
|
110
|
+
if len(shape_list) == 4:
|
|
111
|
+
# Standard: [2, num_layers, num_tokens, hidden_dim]
|
|
112
|
+
# or MLA: [1, num_layers, num_tokens, hidden_dim]
|
|
113
|
+
token_dim = 2
|
|
114
|
+
num_tokens = bytes_read // self.single_token_size
|
|
115
|
+
else:
|
|
116
|
+
# Layerwise 3D: [num_tokens, 2, hidden_dim]
|
|
117
|
+
# Layerwise MLA 2D: [num_tokens, hidden_dim]
|
|
118
|
+
token_dim = 0
|
|
119
|
+
# single_token_size spans ALL layers, but bytes_read is
|
|
120
|
+
# for a single layer. Compute per-layer token size from
|
|
121
|
+
# the non-token dimensions of the shape.
|
|
122
|
+
elements_per_token = 1
|
|
123
|
+
for i in range(1, len(shape_list)):
|
|
124
|
+
elements_per_token *= shape_list[i]
|
|
125
|
+
assert memory_obj.meta.dtype is not None
|
|
126
|
+
dtype_size = memory_obj.meta.dtype.itemsize
|
|
127
|
+
per_layer_token_size = elements_per_token * dtype_size
|
|
128
|
+
num_tokens = bytes_read // per_layer_token_size
|
|
129
|
+
shape_list[token_dim] = num_tokens
|
|
130
|
+
actual_shape = torch.Size(shape_list)
|
|
131
|
+
memory_obj.raw_data = memory_obj.raw_data[:bytes_read]
|
|
132
|
+
memory_obj.meta.shape = actual_shape
|
|
133
|
+
# Sync group_prefix_sum so that get_size() / byte_array reflect the
|
|
134
|
+
# truncated size rather than the original full-chunk size.
|
|
135
|
+
if hasattr(memory_obj, "group_prefix_sum"):
|
|
136
|
+
memory_obj.group_prefix_sum = [0, bytes_read] # type: ignore[attr-defined]
|
|
137
|
+
|
|
138
|
+
return memory_obj
|
|
139
|
+
|
|
140
|
+
@NotAudit
|
|
141
|
+
def post_init(self):
|
|
142
|
+
"""
|
|
143
|
+
Post-initialization method to be called after the connector is created.
|
|
144
|
+
This can be used to perform any additional setup required by the connector.
|
|
145
|
+
"""
|
|
146
|
+
logger.info("Dummy post-initializing remote connector")
|
|
147
|
+
|
|
148
|
+
@abc.abstractmethod
|
|
149
|
+
async def exists(self, key: CacheEngineKey) -> bool:
|
|
150
|
+
"""
|
|
151
|
+
Check if the remote server contains the key
|
|
152
|
+
|
|
153
|
+
Input:
|
|
154
|
+
key: a CacheEngineKey
|
|
155
|
+
|
|
156
|
+
Returns:
|
|
157
|
+
True if the cache engine contains the key, False otherwise
|
|
158
|
+
"""
|
|
159
|
+
raise NotImplementedError
|
|
160
|
+
|
|
161
|
+
@abc.abstractmethod
|
|
162
|
+
def exists_sync(self, key: CacheEngineKey) -> bool:
|
|
163
|
+
"""
|
|
164
|
+
Check if the remote server contains the key synchronized
|
|
165
|
+
|
|
166
|
+
Input:
|
|
167
|
+
key: a CacheEngineKey
|
|
168
|
+
|
|
169
|
+
Returns:
|
|
170
|
+
True if the cache engine contains the key, False otherwise
|
|
171
|
+
"""
|
|
172
|
+
raise NotImplementedError
|
|
173
|
+
|
|
174
|
+
@abc.abstractmethod
|
|
175
|
+
async def get(self, key: CacheEngineKey) -> Optional[MemoryObj]:
|
|
176
|
+
"""
|
|
177
|
+
Get the memory_obj of the corresponding key
|
|
178
|
+
|
|
179
|
+
Input:
|
|
180
|
+
key: the key of the corresponding object
|
|
181
|
+
|
|
182
|
+
Returns:
|
|
183
|
+
The memory_obj of the corresponding key
|
|
184
|
+
Return None if the key does not exist
|
|
185
|
+
"""
|
|
186
|
+
raise NotImplementedError
|
|
187
|
+
|
|
188
|
+
@abc.abstractmethod
|
|
189
|
+
async def put(self, key: CacheEngineKey, memory_obj: MemoryObj):
|
|
190
|
+
"""
|
|
191
|
+
Send the memory_obj with the corresponding key directly
|
|
192
|
+
to the remote server. Will decrease the ref count after
|
|
193
|
+
send finishes.
|
|
194
|
+
|
|
195
|
+
Input:
|
|
196
|
+
key: the CacheEngine key
|
|
197
|
+
memory_obj: the memory_obj of the corresponding key
|
|
198
|
+
"""
|
|
199
|
+
raise NotImplementedError
|
|
200
|
+
|
|
201
|
+
@abc.abstractmethod
|
|
202
|
+
async def list(self) -> List[str]:
|
|
203
|
+
"""
|
|
204
|
+
List all keys in the remote server
|
|
205
|
+
|
|
206
|
+
Returns:
|
|
207
|
+
A list of keys in the remote server
|
|
208
|
+
"""
|
|
209
|
+
raise NotImplementedError
|
|
210
|
+
|
|
211
|
+
@abc.abstractmethod
|
|
212
|
+
async def close(self):
|
|
213
|
+
"""
|
|
214
|
+
Close remote server
|
|
215
|
+
|
|
216
|
+
"""
|
|
217
|
+
raise NotImplementedError
|
|
218
|
+
|
|
219
|
+
def support_ping(self) -> bool:
|
|
220
|
+
"""
|
|
221
|
+
Check if the connector supports ping operation
|
|
222
|
+
|
|
223
|
+
Returns:
|
|
224
|
+
True if ping is supported, False otherwise
|
|
225
|
+
"""
|
|
226
|
+
return False
|
|
227
|
+
|
|
228
|
+
async def ping(self) -> int:
|
|
229
|
+
"""
|
|
230
|
+
Ping the remote server
|
|
231
|
+
|
|
232
|
+
Returns:
|
|
233
|
+
The error code, 0 means success
|
|
234
|
+
"""
|
|
235
|
+
raise NotImplementedError
|
|
236
|
+
|
|
237
|
+
def support_batched_get(self) -> bool:
|
|
238
|
+
"""
|
|
239
|
+
Check if the connector supports batched get
|
|
240
|
+
|
|
241
|
+
Returns:
|
|
242
|
+
True if batched get is supported, False otherwise
|
|
243
|
+
"""
|
|
244
|
+
return False
|
|
245
|
+
|
|
246
|
+
async def batched_get(
|
|
247
|
+
self, keys: List[CacheEngineKey]
|
|
248
|
+
) -> List[Optional[MemoryObj]]:
|
|
249
|
+
"""
|
|
250
|
+
Batched get the memory_objs of the corresponding keys
|
|
251
|
+
|
|
252
|
+
Input:
|
|
253
|
+
keys: the keys of the corresponding objects
|
|
254
|
+
|
|
255
|
+
Returns:
|
|
256
|
+
The memory_objs of the corresponding keys
|
|
257
|
+
Return None if the key does not exist
|
|
258
|
+
"""
|
|
259
|
+
raise NotImplementedError
|
|
260
|
+
|
|
261
|
+
def support_batched_put(self) -> bool:
|
|
262
|
+
"""
|
|
263
|
+
Check if the connector supports batched put
|
|
264
|
+
Returns:
|
|
265
|
+
True if batched put is supported, False otherwise
|
|
266
|
+
"""
|
|
267
|
+
return False
|
|
268
|
+
|
|
269
|
+
async def batched_put(
|
|
270
|
+
self, keys: List[CacheEngineKey], memory_objs: List[MemoryObj]
|
|
271
|
+
):
|
|
272
|
+
"""
|
|
273
|
+
Batched put the memory_objs with the corresponding keys
|
|
274
|
+
Input:
|
|
275
|
+
keys: the keys of the corresponding objects
|
|
276
|
+
memory_objs: the memory_objs of the corresponding keys
|
|
277
|
+
"""
|
|
278
|
+
raise NotImplementedError
|
|
279
|
+
|
|
280
|
+
def support_batched_async_contains(self) -> bool:
|
|
281
|
+
return True
|
|
282
|
+
|
|
283
|
+
async def batched_async_contains(
|
|
284
|
+
self,
|
|
285
|
+
lookup_id: str,
|
|
286
|
+
keys: List[CacheEngineKey],
|
|
287
|
+
pin: bool = False,
|
|
288
|
+
) -> int:
|
|
289
|
+
"""Check how many keys exist in file system in batch
|
|
290
|
+
|
|
291
|
+
Args:
|
|
292
|
+
lookup_id: Identifier for this lookup operation
|
|
293
|
+
keys: List of keys to check
|
|
294
|
+
pin: Whether to pin the keys (not used in FS connector)
|
|
295
|
+
|
|
296
|
+
Returns:
|
|
297
|
+
Number of consecutive keys that exist, starting from the first key
|
|
298
|
+
"""
|
|
299
|
+
tasks = [self.exists(key) for key in keys]
|
|
300
|
+
results = await asyncio.gather(*tasks)
|
|
301
|
+
if False in results:
|
|
302
|
+
return results.index(False)
|
|
303
|
+
return len(results)
|
|
304
|
+
|
|
305
|
+
def support_batched_get_non_blocking(self) -> bool:
|
|
306
|
+
return True
|
|
307
|
+
|
|
308
|
+
async def batched_get_non_blocking(
|
|
309
|
+
self,
|
|
310
|
+
lookup_id: str,
|
|
311
|
+
keys: List[CacheEngineKey],
|
|
312
|
+
) -> List[MemoryObj]:
|
|
313
|
+
"""Batched get the memory_objs of the corresponding keys (non-blocking)
|
|
314
|
+
|
|
315
|
+
This method returns only the consecutive prefix of successfully retrieved
|
|
316
|
+
memory objects. Once a key is not found (None) or an exception occurs,
|
|
317
|
+
all subsequent memory objects (even if successfully retrieved) will be
|
|
318
|
+
released to avoid memory leaks, and only the prefix before the first
|
|
319
|
+
failure will be returned.
|
|
320
|
+
|
|
321
|
+
Args:
|
|
322
|
+
lookup_id: Identifier for this lookup operation
|
|
323
|
+
keys: List of keys to get
|
|
324
|
+
|
|
325
|
+
Returns:
|
|
326
|
+
List of consecutive memory objects from the beginning until the first
|
|
327
|
+
failure (None or Exception). Empty list if the first key fails.
|
|
328
|
+
"""
|
|
329
|
+
# Use asyncio.gather to fetch all keys concurrently
|
|
330
|
+
results = await asyncio.gather(
|
|
331
|
+
*(self.get(key) for key in keys), return_exceptions=True
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
# Only return consecutive prefix of valid memory objects
|
|
335
|
+
memory_objs = []
|
|
336
|
+
found_failure = False
|
|
337
|
+
for result in results:
|
|
338
|
+
if found_failure:
|
|
339
|
+
# Release subsequent memory objects to avoid memory leak
|
|
340
|
+
if isinstance(result, MemoryObj):
|
|
341
|
+
result.ref_count_down()
|
|
342
|
+
elif isinstance(result, MemoryObj):
|
|
343
|
+
memory_objs.append(result)
|
|
344
|
+
else:
|
|
345
|
+
# First failure encountered (None or Exception)
|
|
346
|
+
if isinstance(result, Exception):
|
|
347
|
+
logger.warning(f"Exception during batched get: {result}")
|
|
348
|
+
found_failure = True
|
|
349
|
+
|
|
350
|
+
return memory_objs
|
|
351
|
+
|
|
352
|
+
def remove_sync(self, key: CacheEngineKey) -> bool:
|
|
353
|
+
"""
|
|
354
|
+
Remove a memory object.
|
|
355
|
+
|
|
356
|
+
:param CacheEngineKey key: The key of the MemoryObj.
|
|
357
|
+
|
|
358
|
+
:return: a bool indicates whether remove is successful.
|
|
359
|
+
"""
|
|
360
|
+
raise NotImplementedError
|
|
361
|
+
|
|
362
|
+
def batched_contains(self, keys: List[CacheEngineKey]) -> int:
|
|
363
|
+
"""
|
|
364
|
+
Batched contains.
|
|
365
|
+
|
|
366
|
+
:param List[CacheEngineKey] keys: The keys to check.
|
|
367
|
+
|
|
368
|
+
:return: Return hit chunks by prefix match.
|
|
369
|
+
"""
|
|
370
|
+
raise NotImplementedError
|
|
371
|
+
|
|
372
|
+
def support_batched_contains(self) -> bool:
|
|
373
|
+
"""
|
|
374
|
+
Is supported batched_contains
|
|
375
|
+
"""
|
|
376
|
+
return False
|
|
377
|
+
|
|
378
|
+
def __repr__(self) -> str:
|
|
379
|
+
return f"<{self.__class__.__name__}>"
|